www.gusucode.com > VC++ 车牌定位与识别源码程序 > VC++ 车牌定位与识别源码程序/code/PlateReco/GlobalFunction.cpp

    //Download by http://www.NewXing.com

/**************************************************************************
 *  文件名:GlobalFunction.cpp
 *
 *  图像处理API函数库:
 *
 *  LinerTrans()		- 图像线性变换
 *	WindowTrans()		- 图像窗口变换

 *  GrayStretch()		- 图像灰度拉伸
 *  InteEqualize()		-直方图均衡

 *  ZoomDIB()			- 图像缩放
 *  RotateDIB()			- 图像旋转

 *  ErosionDIB()		- 图像腐蚀
 *  DilationDIB()		- 图像膨胀
 *  OpenDIB()			- 图像开运算
 *  CloseDIB()			- 图像闭运算
 *  ThiningDIB()		- 图像细化 

 *  RobertDIB()			- robert边缘检测运算
 *  SobelDIB()			- sobel边缘检测运算
 *  PrewittDIB()		- prewitt边缘检测运算
 *  KirschDIB()			- kirsch边缘检测运算
 *  GaussDIB()			- gauss边缘检测运算
 *
 *  Template()			- 图像模板变换,通过改变模板,可以用它实现
 *						  图像的平滑、锐化、边缘识别等操作。
 *  MedianFilter()		- 图像中值滤波。
 *  GetMedianNum()		- 获取中值。被函数MedianFilter()调用来求中值。
 *
 *  RowScanDIB()        - 基于行扫描的车牌提取 
 *  CharacterUnit()     - 字符归一化
 *
 *  BpTrain()           - BP网络训练
 *  BpReco()            - BP网络识别
 *
 *  ContourDIB()		- 轮廓提取
 *  TraceDIB()			- 轮廓跟踪
 *
 *  FFT()				- 快速付立叶变换
 *  IFFT()				- 快速付立叶反变换
 *  DCT()				- 离散余弦变换
 *  WALSH()				- 沃尔什-哈达玛变换
 *
 *  Fourier()			- 图像的付立叶变换
 *  DIBDct()			- 图像的离散余弦变换
 *  DIBWalsh()			- 图像的沃尔什-哈达玛变换
 *
 *  ThresholdDIB()		- 图像阈值分割运算
 *  AddMinusDIB()		- 图像加减运算
 *  HprojectDIB()		- 图像水平投影
 *  VprojectDIB()		- 图像垂直投影
 *	TemplateDIB()		- 图像模板匹配运算
 *
 *  Distance13()        - 计算距离图像点最近的段
 *  CharExtract13Sect() - 13段投影法特征提取
 *  DistanceStruct()    - 微结构特征提取法中求待识字符
                        - 特征向量与字典中各特征向量间
						- 的最小距离
 *************************************************************************/

#include "stdafx.h"
#include "Dibapi.h"

#include <math.h>
#include <direct.h>

/*************************************************************************
 *
 * 函数名称:
 *   LinerTrans()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   FLOAT fA		    - 线性变换的斜率
 *   FLOAT fB           - 线性变换的截距
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行灰度的线性变换操作。
 *
 ************************************************************************/

BOOL WINAPI LinerTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, FLOAT fA, FLOAT fB)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 中间变量
	FLOAT	fTemp;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 线性变换
			fTemp = fA * (*lpSrc) + fB;
			
			// 判断是否超出范围
			if (fTemp > 255)
			{
				// 直接赋值为255
				*lpSrc = 255;
			}
			else if (fTemp < 0)
			{
				// 直接赋值为0
				*lpSrc = 0;
			}
			else
			{
				// 四舍五入
				*lpSrc = (unsigned char) (fTemp + 0.5);
			}
		}
	}
	
	// 返回
	return TRUE;

}

/*************************************************************************
 *
 * 函数名称:
 *   ThresholdTrans()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   BYTE  bThre	    - 阈值
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行阈值变换。对于灰度值小于阈值的象素直接设置
 * 灰度值为0;灰度值大于阈值的象素直接设置为255。
 *
 ************************************************************************/
BOOL WINAPI ThresholdTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bThre)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 判断是否小于阈值
			if ((*lpSrc) < bThre)
			{
				// 直接赋值为0
				*lpSrc = 0;
			}
			else
			{
				// 直接赋值为255
				*lpSrc = 255;
			}
		}
	}
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   WindowTrans()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   BYTE  bLow		    - 窗口下限
 *   BYTE  bUp          - 窗口上限
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行窗口变换。只有在窗口范围内的灰度保持不变,
 * 小于下限的象素直接设置灰度值为0;大于上限的象素直接设置灰度值为255。
 *
 ************************************************************************/
BOOL WINAPI WindowTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bLow, BYTE bUp)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 判断是否超出范围
			if ((*lpSrc) < bLow)
			{
				// 直接赋值为0
				*lpSrc = 0;
			}
			else if ((*lpSrc) > bUp)
			{
				// 直接赋值为255
				*lpSrc = 255;
			}
		}
	}
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   GrayStretch()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   BYTE bX1			- 灰度拉伸第一个点的X坐标
 *   BYTE bY1			- 灰度拉伸第一个点的Y坐标
 *   BYTE bX2			- 灰度拉伸第二个点的X坐标
 *   BYTE bY2			- 灰度拉伸第二个点的Y坐标
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行灰度拉伸。
 *
 ************************************************************************/
BOOL WINAPI GrayStretch(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bX1, BYTE bY1, BYTE bX2, BYTE bY2)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 灰度映射表
	BYTE	bMap[256];
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 计算灰度映射表
	for (i = 0; i <= bX1; i++)
	{
		// 判断bX1是否大于0(防止分母为0)
		if (bX1 > 0)
		{
			// 线性变换
			bMap[i] = (BYTE) bY1 * i / bX1;
		}
		else
		{
			// 直接赋值为0
			bMap[i] = 0;
		}
	}
	for (; i <= bX2; i++)
	{
		// 判断bX1是否等于bX2(防止分母为0)
		if (bX2 != bX1)
		{
			// 线性变换
			bMap[i] = bY1 + (BYTE) ((bY2 - bY1) * (i - bX1) / (bX2 - bX1));
		}
		else
		{
			// 直接赋值为bY1
			bMap[i] = bY1;
		}
	}
	for (; i < 256; i++)
	{
		// 判断bX2是否等于255(防止分母为0)
		if (bX2 != 255)
		{
			// 线性变换
			bMap[i] = bY2 + (BYTE) ((255 - bY2) * (i - bX2) / (255 - bX2));
		}
		else
		{
			// 直接赋值为255
			bMap[i] = 255;
		}
	}
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 计算新的灰度值
			*lpSrc = bMap[*lpSrc];
		}
	}
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   InteEqualize()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行直方图均衡。
 *
 ************************************************************************/
BOOL WINAPI InteEqualize(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 临时变量
	LONG	lTemp;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 灰度映射表
	BYTE	bMap[256];
	
	// 灰度映射表
	LONG	lCount[256];
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 重置计数为0
	for (i = 0; i < 256; i ++)
	{
		// 清零
		lCount[i] = 0;
	}
	
	// 计算各个灰度值的计数
	for (i = 0; i < lHeight; i ++)
	{
		for (j = 0; j < lWidth; j ++)
		{
			lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
			
			// 计数加1
			lCount[*(lpSrc)]++;
		}
	}
	
	// 计算灰度映射表
	for (i = 0; i < 256; i++)
	{
		// 初始为0
		lTemp = 0;
		
		for (j = 0; j <= i ; j++)
		{
			lTemp += lCount[j];
		}
		
		// 计算对应的新灰度值
		bMap[i] = (BYTE) (lTemp * 255 / lHeight / lWidth);
	}
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 计算新的灰度值
			*lpSrc = bMap[*lpSrc];
		}
	}
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   ZoomDIB()
 *
 * 参数:
 *   LPSTR lpDIB		- 指向源DIB的指针
 *   float fXZoomRatio	- X轴方向缩放比率
 *   float fYZoomRatio	- Y轴方向缩放比率
 *
 * 返回值:
 *   HGLOBAL            - 缩放成功返回新DIB句柄,否则返回NULL。
 *
 * 说明:
 *   该函数用来缩放DIB图像,返回新生成DIB的句柄。
 *
 ************************************************************************/

HGLOBAL WINAPI ZoomDIB(LPSTR lpDIB, float fXZoomRatio, float fYZoomRatio)
{
	
	// 源图像的宽度和高度
	LONG	lWidth;
	LONG	lHeight;
	
	// 缩放后图像的宽度和高度
	LONG	lNewWidth;
	LONG	lNewHeight;
	
	// 缩放后图像的宽度(lNewWidth',必须是4的倍数)
	LONG	lNewLineBytes;
	
	// 指向源图像的指针
	LPSTR	lpDIBBits;
	
	// 指向源象素的指针
	LPSTR	lpSrc;
	
	// 缩放后新DIB句柄
	HDIB	hDIB;
	
	// 指向缩放图像对应象素的指针
	LPSTR	lpDst;
	
	// 指向缩放图像的指针
	LPSTR	lpNewDIB;
	LPSTR	lpNewDIBBits;
	
	// 指向BITMAPINFO结构的指针(Win3.0)
	LPBITMAPINFOHEADER lpbmi;
	
	// 指向BITMAPCOREINFO结构的指针
	LPBITMAPCOREHEADER lpbmc;
	
	// 循环变量(象素在新DIB中的坐标)
	LONG	i;
	LONG	j;
	
	// 象素在源DIB中的坐标
	LONG	i0;
	LONG	j0;
	
	// 图像每行的字节数
	LONG lLineBytes;
	
	// 找到源DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 获取图像的宽度
	lWidth = ::DIBWidth(lpDIB);
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 获取图像的高度
	lHeight = ::DIBHeight(lpDIB);
	
	// 计算缩放后的图像实际宽度
	// 此处直接加0.5是由于强制类型转换时不四舍五入,而是直接截去小数部分
	lNewWidth = (LONG) (::DIBWidth(lpDIB) * fXZoomRatio + 0.5);
	
	// 计算新图像每行的字节数
	lNewLineBytes = WIDTHBYTES(lNewWidth * 8);
	
	// 计算缩放后的图像高度
	lNewHeight = (LONG) (lHeight * fYZoomRatio + 0.5);
	
	// 分配内存,以保存新DIB
	hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
	
	// 判断是否内存分配失败
	if (hDIB == NULL)
	{
		// 分配内存失败
		return NULL;
	}
	
	// 锁定内存
	lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hDIB);
	
	// 复制DIB信息头和调色板
	memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
	
	// 找到新DIB象素起始位置
	lpNewDIBBits = ::FindDIBBits(lpNewDIB);
	
	// 获取指针
	lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
	lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
	
	// 更新DIB中图像的高度和宽度
	if (IS_WIN30_DIB(lpNewDIB))
	{
		// 对于Windows 3.0 DIB
		lpbmi->biWidth = lNewWidth;
		lpbmi->biHeight = lNewHeight;
	}
	else
	{
		// 对于其它格式的DIB
		lpbmc->bcWidth = (unsigned short) lNewWidth;
		lpbmc->bcHeight = (unsigned short) lNewHeight;
	}
	
	// 针对图像每行进行操作
	for(i = 0; i < lNewHeight; i++)
	{
		// 针对图像每列进行操作
		for(j = 0; j < lNewWidth; j++)
		{
			
			// 指向新DIB第i行,第j个象素的指针
			// 注意此处宽度和高度是新DIB的宽度和高度
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i) + j;
			
			// 计算该象素在源DIB中的坐标
			i0 = (LONG) (i / fYZoomRatio + 0.5);
			j0 = (LONG) (j / fXZoomRatio + 0.5);
			
			// 判断是否在源图范围内
			if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight))
			{
				
				// 指向源DIB第i0行,第j0个象素的指针
				lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight - 1 - i0) + j0;
				
				// 复制象素
				*lpDst = *lpSrc;
			}
			else
			{
				// 对于源图中没有的象素,直接赋值为255
				* ((unsigned char*)lpDst) = 255;
			}
			
		}
		
	}
	
	// 返回
	return hDIB;
}

/*************************************************************************
 *
 * 函数名称:
 *   RotateDIB()
 *
 * 参数:
 *   LPSTR lpDIB		- 指向源DIB的指针
 *   int iRotateAngle	- 旋转的角度(0-360度)
 *
 * 返回值:
 *   HGLOBAL            - 旋转成功返回新DIB句柄,否则返回NULL。
 *
 * 说明:
 *   该函数用来以图像中心为中心旋转DIB图像,返回新生成DIB的句柄。
 * 调用该函数会自动扩大图像以显示所有的象素。函数中采用最邻近插
 * 值算法进行插值。
 *
 ************************************************************************/

HGLOBAL WINAPI RotateDIB(LPSTR lpDIB, int iRotateAngle)
{
	
	// 源图像的宽度和高度
	LONG	lWidth;
	LONG	lHeight;
	
	// 旋转后图像的宽度和高度
	LONG	lNewWidth;
	LONG	lNewHeight;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 旋转后图像的宽度(lNewWidth',必须是4的倍数)
	LONG	lNewLineBytes;
	
	// 指向源图像的指针
	LPSTR	lpDIBBits;
	
	// 指向源象素的指针
	LPSTR	lpSrc;
	
	// 旋转后新DIB句柄
	HDIB	hDIB;
	
	// 指向旋转图像对应象素的指针
	LPSTR	lpDst;
	
	// 指向旋转图像的指针
	LPSTR	lpNewDIB;
	LPSTR	lpNewDIBBits;
	
	// 指向BITMAPINFO结构的指针(Win3.0)
	LPBITMAPINFOHEADER lpbmi;
	
	// 指向BITMAPCOREINFO结构的指针
	LPBITMAPCOREHEADER lpbmc;
	
	// 循环变量(象素在新DIB中的坐标)
	LONG	i;
	LONG	j;
	
	// 象素在源DIB中的坐标
	LONG	i0;
	LONG	j0;
	
	// 旋转角度(弧度)
	float	fRotateAngle;
	
	// 旋转角度的正弦和余弦
	float	fSina, fCosa;
	
	// 源图四个角的坐标(以图像中心为坐标系原点)
	float	fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
	
	// 旋转后四个角的坐标(以图像中心为坐标系原点)
	float	fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
	
	// 两个中间常量
	float	f1,f2;
	
	// 找到源DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 获取图像的"宽度"(4的倍数)
	lWidth = ::DIBWidth(lpDIB);
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 获取图像的高度
	lHeight = ::DIBHeight(lpDIB);
	
	// 将旋转角度从度转换到弧度
	fRotateAngle = (float) RADIAN(iRotateAngle);
	
	// 计算旋转角度的正弦
	fSina = (float) sin((double)fRotateAngle);
	
	// 计算旋转角度的余弦
	fCosa = (float) cos((double)fRotateAngle);
	
	// 计算原图的四个角的坐标(以图像中心为坐标系原点)
	fSrcX1 = (float) (- (lWidth  - 1) / 2);
	fSrcY1 = (float) (  (lHeight - 1) / 2);
	fSrcX2 = (float) (  (lWidth  - 1) / 2);
	fSrcY2 = (float) (  (lHeight - 1) / 2);
	fSrcX3 = (float) (- (lWidth  - 1) / 2);
	fSrcY3 = (float) (- (lHeight - 1) / 2);
	fSrcX4 = (float) (  (lWidth  - 1) / 2);
	fSrcY4 = (float) (- (lHeight - 1) / 2);
	
	// 计算新图四个角的坐标(以图像中心为坐标系原点)
	fDstX1 =  fCosa * fSrcX1 + fSina * fSrcY1;
	fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
	fDstX2 =  fCosa * fSrcX2 + fSina * fSrcY2;
	fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
	fDstX3 =  fCosa * fSrcX3 + fSina * fSrcY3;
	fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
	fDstX4 =  fCosa * fSrcX4 + fSina * fSrcY4;
	fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;
	
	// 计算旋转后的图像实际宽度
	lNewWidth  = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);
	
	// 计算新图像每行的字节数
	lNewLineBytes = WIDTHBYTES(lNewWidth * 8);
	
	// 计算旋转后的图像高度
	lNewHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) )  + 0.5);
	
	// 两个常数,这样不用以后每次都计算了
	f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina
		+ 0.5 * (lWidth  - 1));
	f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa
		+ 0.5 * (lHeight - 1));
	
	// 分配内存,以保存新DIB
	hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
	
	// 判断是否内存分配失败
	if (hDIB == NULL)
	{
		// 分配内存失败
		return NULL;
	}

	// 锁定内存
	lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hDIB);
	
	// 复制DIB信息头和调色板
	memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
	
	// 找到新DIB象素起始位置
	lpNewDIBBits = ::FindDIBBits(lpNewDIB);
	
	// 获取指针
	lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
	lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;

	// 更新DIB中图像的高度和宽度
	if (IS_WIN30_DIB(lpNewDIB))
	{
		// 对于Windows 3.0 DIB
		lpbmi->biWidth = lNewWidth;
		lpbmi->biHeight = lNewHeight;
	}
	else
	{
		// 对于其它格式的DIB
		lpbmc->bcWidth = (unsigned short) lNewWidth;
		lpbmc->bcHeight = (unsigned short) lNewHeight;
	}
	
	// 针对图像每行进行操作
	for(i = 0; i < lNewHeight; i++)
	{
		// 针对图像每列进行操作
		for(j = 0; j < lNewWidth; j++)
		{
			// 指向新DIB第i行,第j个象素的指针
			// 注意此处宽度和高度是新DIB的宽度和高度
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i) + j;
			
			// 计算该象素在源DIB中的坐标
			i0 = (LONG) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5);
			j0 = (LONG) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5);
			
			// 判断是否在源图范围内
			if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight))
			{
				// 指向源DIB第i0行,第j0个象素的指针
				lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight - 1 - i0) + j0;
				
				// 复制象素
				*lpDst = *lpSrc;
			}
			else
			{
				// 对于源图中没有的象素,直接赋值为255
				* ((unsigned char*)lpDst) = 255;
			}
			
		}
		
	}
	
	// 返回
	return hDIB;
}

/*************************************************************************
 *
 * 函数名称:
 *   ErosiontionDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   nMode		- 腐蚀方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。
 *	 int   structure[3][3]
						- 自定义的3×3结构元素。
 *
 * 返回值:
 *   BOOL               - 腐蚀成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行腐蚀运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点;
 * 或者由用户自己定义3×3的结构元素。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI ErosionDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3])
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;
	int  n;
	int  m;

	//像素值
	unsigned char pixel;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	if(nMode == 0)
	{
		//使用水平方向的结构元素进行腐蚀
		for(j = 0; j <lHeight; j++)
		{
			for(i = 1;i <lWidth-1; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;
				
				//目标图像中的当前点先赋成黑色
				*lpDst = (unsigned char)0;

				//如果源图像中当前点自身或者左右有一个点不是黑色,
				//则将目标图像中的当前点赋成白色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+n-1);
					if (pixel == 255 )
					{
						*lpDst = (unsigned char)255;
						break;
					}
				}
				
			}
		}

	}
	else if(nMode == 1)
	{
		//使用垂直方向的结构元素进行腐蚀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成黑色
				*lpDst = (unsigned char)0;

				//如果源图像中当前点自身或者上下有一个点不是黑色,
				//则将目标图像中的当前点赋成白色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+(n-1)*lWidth);
					if (pixel == 255 )
					{
						*lpDst = (unsigned char)255;
						break;
					}
				}
				
			}
		}

	}
	else
	{
		//使用自定义的结构元素进行腐蚀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素
				//和最上边和最下边的两列像素
				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成黑色
				*lpDst = (unsigned char)0;

				//如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色,
				//则将目标图像中的当前点赋成白色
				//注意在DIB图像中内容是上下倒置的
				for (m = 0;m < 3;m++ )
				{
					for (n = 0;n < 3;n++)
					{
						if( structure[m][n] == -1)
							continue;
						pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1));
						if (pixel == 255 )
						{	
							*lpDst = (unsigned char)255;
							break;
						}
					}
				}
				
			}
		}

	}
	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}




/*************************************************************************
 *
 * 函数名称:
 *   DilationDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   nMode		- 膨胀方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。
 *	 int   structure[3][3]
						- 自定义的3×3结构元素。
 *
 * 返回值:
 *   BOOL               - 膨胀成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行膨胀运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点;
 * 或者由用户自己定义3×3的结构元素。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/


BOOL WINAPI DilationDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3])
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;
	int  n;
	int  m;

	//像素值
	unsigned char pixel;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	if(nMode == 0)
	{
		//使用水平方向的结构元素进行膨胀
		for(j = 0; j <lHeight; j++)
		{
			for(i = 1;i <lWidth-1; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && pixel != 0)
					return FALSE;
				
				//目标图像中的当前点先赋成白色
				*lpDst = (unsigned char)255;

				//源图像中当前点自身或者左右只要有一个点是黑色,
				//则将目标图像中的当前点赋成黑色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+n-1);
					if (pixel == 0 )
					{
						*lpDst = (unsigned char)0;
						break;
					}
				}
				
			}
		}

	}
	else if(nMode == 1)
	{
		//使用垂直方向的结构元素进行膨胀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成白色
				*lpDst = (unsigned char)255;

				//源图像中当前点自身或者上下只要有一个点是黑色,
				//则将目标图像中的当前点赋成黑色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+(n-1)*lWidth);
					if (pixel == 0 )
					{
						*lpDst = (unsigned char)0;
						break;
					}
				}
				
			}
		}

	}
	else
	{
		//使用自定义的结构元素进行膨胀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素
				//和最上边和最下边的两列像素
				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成白色
				*lpDst = (unsigned char)255;

				//原图像中对应结构元素中为黑色的那些点中只要有一个是黑色,
				//则将目标图像中的当前点赋成黑色
				//注意在DIB图像中内容是上下倒置的
				for (m = 0;m < 3;m++ )
				{
					for (n = 0;n < 3;n++)
					{
						if( structure[m][n] == -1)
							continue;
						pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1));
						if (pixel == 0 )
						{	
							*lpDst = (unsigned char)0;
							break;
						}
					}
				}
				
			}
		}

	}
	// 复制膨胀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}





/*************************************************************************
 *
 * 函数名称:
 *   OpenDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   nMode		- 开运算方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。
 *	 int   structure[3][3]
						- 自定义的3×3结构元素。
 *
 * 返回值:
 *   BOOL               - 开运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行开运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点;
 * 或者由用户自己定义3×3的结构元素。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI OpenDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3])
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;
	int  n;
	int  m;

	//像素值
	unsigned char pixel;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	if(nMode == 0)
	{
		//使用水平方向的结构元素进行腐蚀
		for(j = 0; j <lHeight; j++)
		{
			for(i = 1;i <lWidth-1; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;
				
				//目标图像中的当前点先赋成黑色
				*lpDst = (unsigned char)0;

				//如果源图像中当前点自身或者左右有一个点不是黑色,
				//则将目标图像中的当前点赋成白色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+n-1);
					if (pixel == 255 )
					{
						*lpDst = (unsigned char)255;
						break;
					}
				}
				
			}
		}

	}
	else if(nMode == 1)
	{
		//使用垂直方向的结构元素进行腐蚀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成黑色
				*lpDst = (unsigned char)0;

				//如果源图像中当前点自身或者上下有一个点不是黑色,
				//则将目标图像中的当前点赋成白色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+(n-1)*lWidth);
					if (pixel == 255 )
					{
						*lpDst = (unsigned char)255;
						break;
					}
				}
				
			}
		}

	}
	else
	{
		//使用自定义的结构元素进行腐蚀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素
				//和最上边和最下边的两列像素
				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成黑色
				*lpDst = (unsigned char)0;

				//如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色,
				//则将目标图像中的当前点赋成白色
				//注意在DIB图像中内容是上下倒置的
				for (m = 0;m < 3;m++ )
				{
					for (n = 0;n < 3;n++)
					{
						if( structure[m][n] == -1)
							continue;
						pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1));
						if (pixel == 255 )
						{	
							*lpDst = (unsigned char)255;
							break;
						}
					}
				}
				
			}
		}

	}
	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 重新初始化新分配的内存,设定初始值为255
	//lpDst = (char *)lpNewDIBBits;
	//memset(lpDst, (BYTE)255, lWidth * lHeight);


	if(nMode == 0)
	{
		//使用水平方向的结构元素进行膨胀
		for(j = 0; j <lHeight; j++)
		{
			for(i = 1;i <lWidth-1; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;
				
				//目标图像中的当前点先赋成白色
				*lpDst = (unsigned char)255;

				//源图像中当前点自身或者左右只要有一个点是黑色,
				//则将目标图像中的当前点赋成黑色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+n-1);
					if (pixel == 0 )
					{
						*lpDst = (unsigned char)0;
						break;
					}
				}
				
			}
		}

	}
	else if(nMode == 1)
	{
		//使用垂直方向的结构元素进行膨胀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成白色
				*lpDst = (unsigned char)255;

				//源图像中当前点自身或者上下只要有一个点是黑色,
				//则将目标图像中的当前点赋成黑色
				for (n = 0;n < 3;n++ )
				{
					pixel = *(lpSrc+(n-1)*lWidth);
					if (pixel == 0 )
					{
						*lpDst = (unsigned char)0;
						break;
					}
				}
				
			}
		}

	}
	else
	{
		//使用自定义的结构元素进行膨胀
		for(j = 1; j <lHeight-1; j++)
		{
			for(i = 0;i <lWidth; i++)
			{
				//由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素
				//和最上边和最下边的两列像素
				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					return FALSE;

				//目标图像中的当前点先赋成白色
				*lpDst = (unsigned char)255;

				//原图像中对应结构元素中为黑色的那些点中只要有一个是黑色,
				//则将目标图像中的当前点赋成黑色
				//注意在DIB图像中内容是上下倒置的
				for (m = 0;m < 3;m++ )
				{
					for (n = 0;n < 3;n++)
					{
						if( structure[m][n] == -1)
							continue;
						pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1));
						if (pixel == 0 )
						{	
							*lpDst = (unsigned char)0;
							break;
						}
					}
				}
				
			}
		}

	}
	// 复制膨胀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);


	return TRUE;
}


/*************************************************************************
 *
 * 函数名称:
 *   CloseDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   nMode		- 闭运算方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。
 *	 int   structure[3][3]
						- 自定义的3×3结构元素。
 *
 * 返回值:
 *   BOOL               - 闭运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行开运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点;
 * 或者由用户自己定义3×3的结构元素。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/


BOOL WINAPI CloseDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3])
{
		if (DilationDIB(lpDIBBits, lWidth, lHeight, nMode , structure))
		{

			if (ErosionDIB(lpDIBBits, lWidth, lHeight, nMode , structure))
			{
				// 返回
				return TRUE;

			}
		}
		return FALSE;
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   ThinDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 闭运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行细化运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI ThiningDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//脏标记
	BOOL bModified;

	//循环变量
	long i;
	long j;
	int  n;
	int  m;

	//四个条件
	BOOL bCondition1;
	BOOL bCondition2;
	BOOL bCondition3;
	BOOL bCondition4;

	//计数器
	unsigned char nCount;
	
	//像素值
	unsigned char pixel;

	//5×5相邻区域像素值
	unsigned char neighbour[5][5];

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	bModified=TRUE;

	while(bModified)
	{

		bModified = FALSE;
		// 初始化新分配的内存,设定初始值为255
		lpDst = (char *)lpNewDIBBits;
		memset(lpDst, (BYTE)255, lWidth * lHeight);

		for(j = 2; j <lHeight-2; j++)
		{
			for(i = 2;i <lWidth-2; i++)
			{

				bCondition1 = FALSE;
				bCondition2 = FALSE;
				bCondition3 = FALSE;
				bCondition4 = FALSE;

				//由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素

				// 指向源图像倒数第j行,第i个象素的指针			
				lpSrc = (char *)lpDIBBits + lWidth * j + i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;

				//取得当前指针处的像素值,注意要转换为unsigned char型
				pixel = (unsigned char)*lpSrc;

				//目标图像中含有0和255外的其它灰度值
				if(pixel != 255 && *lpSrc != 0)
					//return FALSE;
					continue;
				//如果源图像中当前点为白色,则跳过
				else if(pixel == 255)
					continue;

				//获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表
				for (m = 0;m < 5;m++ )
				{
					for (n = 0;n < 5;n++)
					{
						neighbour[m][n] =(255 - (unsigned char)*(lpSrc + ((4 - m) - 2)*lWidth + n - 2 )) / 255;
					}
				}
//				neighbour[][]
				//逐个判断条件。
				//判断2<=NZ(P1)<=6
				nCount =  neighbour[1][1] + neighbour[1][2] + neighbour[1][3] \
						+ neighbour[2][1] + neighbour[2][3] + \
						+ neighbour[3][1] + neighbour[3][2] + neighbour[3][3];
				if ( nCount >= 2 && nCount <=6)
					bCondition1 = TRUE;

				//判断Z0(P1)=1
				nCount = 0;
				if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
					nCount++;
				if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
					nCount++;
				if (neighbour[2][1] == 0 && neighbour[3][1] == 1)
					nCount++;
				if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
					nCount++;
				if (neighbour[3][2] == 0 && neighbour[3][3] == 1)
					nCount++;
				if (neighbour[3][3] == 0 && neighbour[2][3] == 1)
					nCount++;
				if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
					nCount++;
				if (neighbour[1][3] == 0 && neighbour[1][2] == 1)
					nCount++;
				if (nCount == 1)
					bCondition2 = TRUE;

				//判断P2*P4*P8=0 or Z0(p2)!=1
				if (neighbour[1][2]*neighbour[2][1]*neighbour[2][3] == 0)
					bCondition3 = TRUE;
				else
				{
					nCount = 0;
					if (neighbour[0][2] == 0 && neighbour[0][1] == 1)
						nCount++;
					if (neighbour[0][1] == 0 && neighbour[1][1] == 1)
						nCount++;
					if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
						nCount++;
					if (neighbour[2][1] == 0 && neighbour[2][2] == 1)
						nCount++;
					if (neighbour[2][2] == 0 && neighbour[2][3] == 1)
						nCount++;
					if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
						nCount++;
					if (neighbour[1][3] == 0 && neighbour[0][3] == 1)
						nCount++;
					if (neighbour[0][3] == 0 && neighbour[0][2] == 1)
						nCount++;
					if (nCount != 1)
						bCondition3 = TRUE;
				}

				//判断P2*P4*P6=0 or Z0(p4)!=1
				if (neighbour[1][2]*neighbour[2][1]*neighbour[3][2] == 0)
					bCondition4 = TRUE;
				else
				{
					nCount = 0;
					if (neighbour[1][1] == 0 && neighbour[1][0] == 1)
						nCount++;
					if (neighbour[1][0] == 0 && neighbour[2][0] == 1)
						nCount++;
					if (neighbour[2][0] == 0 && neighbour[3][0] == 1)
						nCount++;
					if (neighbour[3][0] == 0 && neighbour[3][1] == 1)
						nCount++;
					if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
						nCount++;
					if (neighbour[3][2] == 0 && neighbour[2][2] == 1)
						nCount++;
					if (neighbour[2][2] == 0 && neighbour[1][2] == 1)
						nCount++;
					if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
						nCount++;
					if (nCount != 1)
						bCondition4 = TRUE;
				}
				if(bCondition1 && bCondition2 && bCondition3 && bCondition4)
				{
					*lpDst = (unsigned char)255;
					bModified = TRUE;
				}
				else
				{
					*lpDst = (unsigned char)0;
				}
			}
		}
			// 复制腐蚀后的图像
			memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);


	}
	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   RobertDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用Robert边缘检测算子对图像进行边缘检测运算。
 * 
 * 要求目标图像为灰度图像。
 ************************************************************************/

BOOL WINAPI RobertDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	//像素值
	double result;
	unsigned char pixel[4];

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	//使用水平方向的结构元素进行腐蚀
	for(j = lHeight-1; j > 0; j--)
	{
		for(i = 0;i <lWidth-1; i++)
		{
			//由于使用2×2的模板,为防止越界,所以不处理最下边和最右边的两列像素

			// 指向源图像第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lWidth * j + i;

			// 指向目标图像第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lWidth * j + i;

			//取得当前指针处2*2区域的像素值,注意要转换为unsigned char型
			pixel[0] = (unsigned char)*lpSrc;
			pixel[1] = (unsigned char)*(lpSrc + 1);
			pixel[2] = (unsigned char)*(lpSrc - lWidth);
			pixel[3] = (unsigned char)*(lpSrc - lWidth + 1);

			//计算目标图像中的当前点
			 result = sqrt(( pixel[0] - pixel[3] )*( pixel[0] - pixel[3] ) + \
				  ( pixel[1] - pixel[2] )*( pixel[1] - pixel[2] ));
			*lpDst = (unsigned char)result;
		
		}
	}

	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   SobelDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用Sobel边缘检测算子对图像进行边缘检测运算。
 * 
 * 要求目标图像为灰度图像。
 ************************************************************************/

BOOL WINAPI SobelDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向缓存图像的指针
	LPSTR	lpDst1;
	LPSTR	lpDst2;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits1;
	HLOCAL	hNewDIBBits1;
	LPSTR	lpNewDIBBits2;
	HLOCAL	hNewDIBBits2;

	//循环变量
	long i;
	long j;

	// 模板高度
	int		iTempH;
	
	// 模板宽度
	int		iTempW;
	
	// 模板系数
	FLOAT	fTempC;
	
	// 模板中心元素X坐标
	int		iTempMX;
	
	// 模板中心元素Y坐标
	int		iTempMY;
	
	//模板数组
	FLOAT aTemplate[9];

	// 暂时分配内存,以保存新图像
	hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1);

	// 暂时分配内存,以保存新图像
	hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits2 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);

	// 拷贝源图像到缓存图像中
	lpDst1 = (char *)lpNewDIBBits1;
	memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight);
	lpDst2 = (char *)lpNewDIBBits2;
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);

	// 设置Sobel模板参数
	iTempW = 3;
	iTempH = 3;
	fTempC = 1.0;
	iTempMX = 1;
	iTempMY = 1;
	aTemplate[0] = -1.0;
	aTemplate[1] = -2.0;
	aTemplate[2] = -1.0;
	aTemplate[3] = 0.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 0.0;
	aTemplate[6] = 1.0;
	aTemplate[7] = 2.0;
	aTemplate[8] = 1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits1, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 设置Sobel模板参数
	aTemplate[0] = -1.0;
	aTemplate[1] = 0.0;
	aTemplate[2] = 1.0;
	aTemplate[3] = -2.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 2.0;
	aTemplate[6] = -1.0;
	aTemplate[7] = 0.0;
	aTemplate[8] = 1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits1);
	LocalFree(hNewDIBBits1);

	LocalUnlock(hNewDIBBits2);
	LocalFree(hNewDIBBits2);
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   PrewittDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用Prewitt边缘检测算子对图像进行边缘检测运算。
 * 
 * 要求目标图像为灰度图像。
 ************************************************************************/

BOOL WINAPI PrewittDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向缓存图像的指针
	LPSTR	lpDst1;
	LPSTR	lpDst2;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits1;
	HLOCAL	hNewDIBBits1;
	LPSTR	lpNewDIBBits2;
	HLOCAL	hNewDIBBits2;

	//循环变量
	long i;
	long j;

	// 模板高度
	int		iTempH;
	
	// 模板宽度
	int		iTempW;
	
	// 模板系数
	FLOAT	fTempC;
	
	// 模板中心元素X坐标
	int		iTempMX;
	
	// 模板中心元素Y坐标
	int		iTempMY;
	
	//模板数组
	FLOAT aTemplate[9];

	// 暂时分配内存,以保存新图像
	hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1);

	// 暂时分配内存,以保存新图像
	hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits2 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);

	// 拷贝源图像到缓存图像中
	lpDst1 = (char *)lpNewDIBBits1;
	memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight);
	lpDst2 = (char *)lpNewDIBBits2;
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);


	// 设置Prewitt模板参数
	iTempW = 3;
	iTempH = 3;
	fTempC = 1.0;
	iTempMX = 1;
	iTempMY = 1;
	aTemplate[0] = -1.0;
	aTemplate[1] = -1.0;
	aTemplate[2] = -1.0;
	aTemplate[3] = 0.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 0.0;
	aTemplate[6] = 1.0;
	aTemplate[7] = 1.0;
	aTemplate[8] = 1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits1, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 设置Prewitt模板参数
	aTemplate[0] = 1.0;
	aTemplate[1] = 0.0;
	aTemplate[2] = -1.0;
	aTemplate[3] = 1.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = -1.0;
	aTemplate[6] = 1.0;
	aTemplate[7] = 0.0;
	aTemplate[8] = -1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits1);
	LocalFree(hNewDIBBits1);

	LocalUnlock(hNewDIBBits2);
	LocalFree(hNewDIBBits2);
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   KirschDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用kirsch边缘检测算子对图像进行边缘检测运算。
 * 
 * 要求目标图像为灰度图像。
 ************************************************************************/

BOOL WINAPI KirschDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向缓存图像的指针
	LPSTR	lpDst1;
	LPSTR	lpDst2;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits1;
	HLOCAL	hNewDIBBits1;
	LPSTR	lpNewDIBBits2;
	HLOCAL	hNewDIBBits2;

	//循环变量
	long i;
	long j;

	// 模板高度
	int		iTempH;
	
	// 模板宽度
	int		iTempW;
	
	// 模板系数
	FLOAT	fTempC;
	
	// 模板中心元素X坐标
	int		iTempMX;
	
	// 模板中心元素Y坐标
	int		iTempMY;
	
	//模板数组
	FLOAT aTemplate[9];

	// 暂时分配内存,以保存新图像
	hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1);

	// 暂时分配内存,以保存新图像
	hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits2 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);

	// 拷贝源图像到缓存图像中
	lpDst1 = (char *)lpNewDIBBits1;
	memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight);
	lpDst2 = (char *)lpNewDIBBits2;
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);


	// 设置Kirsch模板1参数
	iTempW = 3;
	iTempH = 3;
	fTempC = 1.0;
	iTempMX = 1;
	iTempMY = 1;
	aTemplate[0] = 5.0;
	aTemplate[1] = 5.0;
	aTemplate[2] = 5.0;
	aTemplate[3] = -3.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = -3.0;
	aTemplate[6] = -3.0;
	aTemplate[7] = -3.0;
	aTemplate[8] = -3.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits1, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 设置Kirsch模板2参数
	aTemplate[0] = -3.0;
	aTemplate[1] = 5.0;
	aTemplate[2] = 5.0;
	aTemplate[3] = -3.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 5.0;
	aTemplate[6] = -3.0;
	aTemplate[7] = -3.0;
	aTemplate[8] = -3.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);

	// 设置Kirsch模板3参数
	aTemplate[0] = -3.0;
	aTemplate[1] = -3.0;
	aTemplate[2] = 5.0;
	aTemplate[3] = -3.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 5.0;
	aTemplate[6] = -3.0;
	aTemplate[7] = -3.0;
	aTemplate[8] = 5.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);
	
	// 设置Kirsch模板4参数
	aTemplate[0] = -3.0;
	aTemplate[1] = -3.0;
	aTemplate[2] = -3.0;
	aTemplate[3] = -3.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 5.0;
	aTemplate[6] = -3.0;
	aTemplate[7] = 5.0;
	aTemplate[8] = 5.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);
	
	// 设置Kirsch模板5参数
	aTemplate[0] = -3.0;
	aTemplate[1] = -3.0;
	aTemplate[2] = -3.0;
	aTemplate[3] = -3.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = -3.0;
	aTemplate[6] = 5.0;
	aTemplate[7] = 5.0;
	aTemplate[8] = 5.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);
	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);
	
	// 设置Kirsch模板6参数
	aTemplate[0] = -3.0;
	aTemplate[1] = -3.0;
	aTemplate[2] = -3.0;
	aTemplate[3] = 5.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = -3.0;
	aTemplate[6] = 5.0;
	aTemplate[7] = 5.0;
	aTemplate[8] = -3.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);
	
	// 设置Kirsch模板7参数
	aTemplate[0] = 5.0;
	aTemplate[1] = -3.0;
	aTemplate[2] = -3.0;
	aTemplate[3] = 5.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = -3.0;
	aTemplate[6] = 5.0;
	aTemplate[7] = -3.0;
	aTemplate[8] = -3.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 拷贝源图像到缓存图像中
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);
	
	// 设置Kirsch模板8参数
	aTemplate[0] = 5.0;
	aTemplate[1] = 5.0;
	aTemplate[2] = -3.0;
	aTemplate[3] = 5.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = -3.0;
	aTemplate[6] = -3.0;
	aTemplate[7] = -3.0;
	aTemplate[8] = -3.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits1);
	LocalFree(hNewDIBBits1);

	LocalUnlock(hNewDIBBits2);
	LocalFree(hNewDIBBits2);
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *  GaussDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用高斯拉普拉斯边缘检测算子对图像进行边缘检测运算。
 * 
 * 要求目标图像为灰度图像。
 ************************************************************************/

BOOL WINAPI GaussDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向缓存图像的指针
	LPSTR	lpDst1;
	LPSTR	lpDst2;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits1;
	HLOCAL	hNewDIBBits1;
	LPSTR	lpNewDIBBits2;
	HLOCAL	hNewDIBBits2;

	// 模板高度
	int		iTempH;
	
	// 模板宽度
	int		iTempW;
	
	// 模板系数
	FLOAT	fTempC;
	
	// 模板中心元素X坐标
	int		iTempMX;
	
	// 模板中心元素Y坐标
	int		iTempMY;
	
	//模板数组
	FLOAT aTemplate[25];

	// 暂时分配内存,以保存新图像
	hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1);

	// 暂时分配内存,以保存新图像
	hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits2 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);

	// 拷贝源图像到缓存图像中
	lpDst1 = (char *)lpNewDIBBits1;
	memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight);
	lpDst2 = (char *)lpNewDIBBits2;
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);


	// 设置Gauss模板参数
	iTempW = 5;
	iTempH = 5;
	fTempC = 1.0;
	iTempMX = 3;
	iTempMY = 3;
	aTemplate[0] = -2.0;
	aTemplate[1] = -4.0;
	aTemplate[2] = -4.0;
	aTemplate[3] = -4.0;
	aTemplate[4] = -2.0;
	aTemplate[5] = -4.0;
	aTemplate[6] = 0.0;
	aTemplate[7] = 8.0;
	aTemplate[8] = 0.0;
	aTemplate[9] = -4.0;
	aTemplate[10] = -4.0;
	aTemplate[11] = 8.0;
	aTemplate[12] = 24.0;
	aTemplate[13] = 8.0;
	aTemplate[14] = -4.0;
	aTemplate[15] = -4.0;
	aTemplate[16] = 0.0;
	aTemplate[17] = 8.0;
	aTemplate[18] = 0.0;
	aTemplate[19] = -4.0;
	aTemplate[20] = -2.0;
	aTemplate[21] = -4.0;
	aTemplate[22] = -4.0;
	aTemplate[23] = -4.0;
	aTemplate[24] = -2.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits1, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits1);
	LocalFree(hNewDIBBits1);

	LocalUnlock(hNewDIBBits2);
	LocalFree(hNewDIBBits2);
	// 返回
	return TRUE;
}

BOOL WINAPI DifferDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	// 模板高度
	int		iTempH;
	
	// 模板宽度
	int		iTempW;
	
	// 模板系数
	FLOAT	fTempC;
	
	// 模板中心元素X坐标
	int		iTempMX;
	
	// 模板中心元素Y坐标
	int		iTempMY;
	
	//模板数组
	FLOAT aTemplate[3];

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 拷贝源图像到缓存图像中
	lpDst = (char *)lpNewDIBBits;
	memcpy(lpNewDIBBits, lpDIBBits, lWidth * lHeight);

	// 设置Sobel模板参数
	iTempW = 3;
	iTempH = 1;
	fTempC = 1.0;
	iTempMX = 1;
	iTempMY = 0;
	aTemplate[0] = 0.0;
	aTemplate[1] = 1.0;
	aTemplate[2] = -1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);
	// 返回
	return TRUE;

}
/*************************************************************************
 *
 * 函数名称:
 *   Template()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   iTempH		- 模板的高度
 *   int   iTempW		- 模板的宽度
 *   int   iTempMX		- 模板的中心元素X坐标 ( < iTempW - 1)
 *   int   iTempMY		- 模板的中心元素Y坐标 ( < iTempH - 1)
 *	 FLOAT * fpArray	- 指向模板数组的指针
 *	 FLOAT fCoef		- 模板系数
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用指定的模板(任意大小)来对图像进行操作,参数iTempH指定模板
 * 的高度,参数iTempW指定模板的宽度,参数iTempMX和iTempMY指定模板的中心
 * 元素坐标,参数fpArray指定模板元素,fCoef指定系数。
 *
 ************************************************************************/

BOOL WINAPI Template(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, 
					 int iTempH, int iTempW, 
					 int iTempMX, int iTempMY,
					 FLOAT * fpArray, FLOAT fCoef)
{
	// 指向复制图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 指向要复制区域的指针
	unsigned char*	lpDst;
	
	// 循环变量
	LONG	i;
	LONG	j;
	LONG	k;
	LONG	l;
	
	// 计算结果
	FLOAT	fResult;
	
	// 图像每行的字节数
	LONG lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);
	
	// 判断是否内存分配失败
	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
	
	// 初始化图像为原始图像
	memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight);
	
	// 行(除去边缘几行)
	for(i = iTempMY; i < lHeight - iTempH + iTempMY + 1; i++)
	{
		// 列(除去边缘几列)
		for(j = iTempMX; j < lWidth - iTempW + iTempMX + 1; j++)
		{
			// 指向新DIB第i行,第j个象素的指针
			lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			fResult = 0;
			
			// 计算
			for (k = 0; k < iTempH; k++)
			{
				for (l = 0; l < iTempW; l++)
				{
					// 指向DIB第i - iTempMY + k行,第j - iTempMX + l个象素的指针
					lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i + iTempMY - k)
						+ j - iTempMX + l;
					
					// 保存象素值
					fResult += (* lpSrc) * fpArray[k * iTempW + l];
				}
			}
			
			// 乘上系数
			fResult *= fCoef;
			
			// 取绝对值
			fResult = (FLOAT ) fabs(fResult);
			
			// 判断是否超过255
			if(fResult > 255)
			{
				// 直接赋值为255
				* lpDst = 255;
			}
			else
			{
				// 赋值
				* lpDst = (unsigned char) (fResult + 0.5);
			}
			
		}
	}
	
	// 复制变换后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight);
	
	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);
	
	// 返回
	return TRUE;

}

/*************************************************************************
 *
 * 函数名称:
 *   MedianFilter()
 *
 * 参数:
 *   LPSTR lpDIBBits		- 指向源DIB图像指针
 *   LONG  lWidth			- 源图像宽度(象素数)
 *   LONG  lHeight			- 源图像高度(象素数)
 *   int   iFilterH			- 滤波器的高度
 *   int   iFilterW			- 滤波器的宽度
 *   int   iFilterMX		- 滤波器的中心元素X坐标
 *   int   iFilterMY		- 滤波器的中心元素Y坐标
 *
 * 返回值:
 *   BOOL					- 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数对DIB图像进行中值滤波。
 *
 ************************************************************************/

BOOL WINAPI MedianFilter(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, 
						 int iFilterH, int iFilterW, 
						 int iFilterMX, int iFilterMY)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 指向要复制区域的指针
	unsigned char*	lpDst;
	
	// 指向复制图像的指针
	LPSTR			lpNewDIBBits;
	HLOCAL			hNewDIBBits;
	
	// 指向滤波器数组的指针
	unsigned char	* aValue;
	HLOCAL			hArray;
	
	// 循环变量
	LONG			i;
	LONG			j;
	LONG			k;
	LONG			l;
	
	// 图像每行的字节数
	LONG			lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);
	
	// 判断是否内存分配失败
	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
	
	// 初始化图像为原始图像
	memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight);
	
	// 暂时分配内存,以保存滤波器数组
	hArray = LocalAlloc(LHND, iFilterH * iFilterW);
	
	// 判断是否内存分配失败
	if (hArray == NULL)
	{
		// 释放内存
		LocalUnlock(hNewDIBBits);
		LocalFree(hNewDIBBits);
		
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	aValue = (unsigned char * )LocalLock(hArray);
	
	// 开始中值滤波
	// 行(除去边缘几行)
	for(i = iFilterMY; i < lHeight - iFilterH + iFilterMY + 1; i++)
	{
		// 列(除去边缘几列)
		for(j = iFilterMX; j < lWidth - iFilterW + iFilterMX + 1; j++)
		{
			// 指向新DIB第i行,第j个象素的指针
			lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 读取滤波器数组
			for (k = 0; k < iFilterH; k++)
			{
				for (l = 0; l < iFilterW; l++)
				{
					// 指向DIB第i - iFilterMY + k行,第j - iFilterMX + l个象素的指针
					lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i + iFilterMY - k) + j - iFilterMX + l;
					
					// 保存象素值
					aValue[k * iFilterW + l] = *lpSrc;
				}
			}
			
			// 获取中值
			* lpDst = GetMedianNum(aValue, iFilterH * iFilterW);
		}
	}
	
	// 复制变换后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight);
	
	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);
	LocalUnlock(hArray);
	LocalFree(hArray);
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   GetMedianNum()
 *
 * 参数:
 *   unsigned char * bpArray	- 指向要获取中值的数组指针
 *   int   iFilterLen			- 数组长度
 *
 * 返回值:
 *   unsigned char      - 返回指定数组的中值。
 *
 * 说明:
 *   该函数用冒泡法对一维数组进行排序,并返回数组元素的中值。
 *
 ************************************************************************/

unsigned char WINAPI GetMedianNum(unsigned char * bArray, int iFilterLen)
{
	// 循环变量
	int		i;
	int		j;
	
	// 中间变量
	unsigned char bTemp;
	
	// 用冒泡法对数组进行排序
	for (j = 0; j < iFilterLen - 1; j ++)
	{
		for (i = 0; i < iFilterLen - j - 1; i ++)
		{
			if (bArray[i] > bArray[i + 1])
			{
				// 互换
				bTemp = bArray[i];
				bArray[i] = bArray[i + 1];
				bArray[i + 1] = bTemp;
			}
		}
	}
	
	// 计算中值
	if ((iFilterLen & 1) > 0)
	{
		// 数组有奇数个元素,返回中间一个元素
		bTemp = bArray[(iFilterLen + 1) / 2];
	}
	else
	{
		// 数组有偶数个元素,返回中间两个元素平均值
		bTemp = (bArray[iFilterLen / 2] + bArray[iFilterLen / 2 + 1]) / 2;
	}
	
	// 返回中值
	return bTemp;
}

/*************************************************************************
 *
 * 函数名称:
 *   GradSharp()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   BYTE  bThre		- 阈值
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行梯度锐化。
 *
 ************************************************************************/
BOOL WINAPI GradSharp(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bThre)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	unsigned char*	lpSrc1;
	unsigned char*	lpSrc2;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 中间变量
	BYTE	bTemp;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc  = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 指向DIB第i+1行,第j个象素的指针
			lpSrc1 = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 2 - i) + j;
			
			// 指向DIB第i行,第j+1个象素的指针
			lpSrc2 = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j + 1;
			
			bTemp = abs((*lpSrc)-(*lpSrc1)) + abs((*lpSrc)-(*lpSrc2));
			
			// 判断是否小于阈值
			if (bTemp < 255)
			{
				// 判断是否大于阈值,对于小于情况,灰度值不变。
				if (bTemp >= bThre)
				{
					// 直接赋值为bTemp
					*lpSrc = bTemp;
				}
			}
			else
			{
				// 直接赋值为255
				*lpSrc = 255;
			}
		}
	}
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   RowScanDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行水平投影运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

int* RowscanDIB2(LPSTR lpDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine)
{
//	AfxMessageBox("Start...");
	
	// 指向源图像的指针
	LPSTR	lpSrc,lpSrcformer,lpSrclater;

	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 分割后图像的宽度和高度
	LONG	lNewWidth = 140;
	LONG	lNewHeight = 40;

	//循环变量
	long i;
	long j;
	long k;

	// 获取车牌位置信息
	int *pPlatePosi;

	int iPlateLine[40];

	for(i=0;i<40;i++)
	{
		iPlateLine[i]=*pPlateLine;
		pPlateLine++;
	}

	// 图像中每行象素由 0->255 或 255->0 的次数
	long lGrayChangeNumber;

	// 前一个像素值
	unsigned char pixelformer;

	// 后一个像素值
	unsigned char pixellater;

	// 满足条件底行的位置
	int iLineLocation;

	// 连续出现变化次数超过阈值的行数
	int iLineNumber;

	// 满足条件的区域的上界 
	int iTopLine;

	// 满足条件的区域的下界 
	int iLowLine;

	// 满足条件的区域的左边界 
	int iLeftLine;

	// 满足条件的区域的右边界 
	int iRightLine;

	// 图像每行的字节数
	LONG lLineBytes;

	// 新图像每行的字节数
	LONG lNewLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	lNewLineBytes = WIDTHBYTES( lNewWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变

	// 标明是否找到车牌(第一个数),及车牌位置(后四个数)
    int iPlatePosition[5] = {0,0,0,0,0};

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lNewLineBytes * lNewHeight);

	iLineLocation = 0;
	iLineNumber = 0;
	iTopLine = 0;
	iLowLine = 0;

	// 记录满足条件的行的位置
	int iLineNum[100];
	for(i=0;i<100;i++)
	{
		iLineNum[i]=0;
	}
	int iLineNum1;
	iLineNum1 = 0;
	//int a1,a2,b1,b2;
	// 初步寻找满足条件的行,条件1:在一行内存在一连续的长度约为140的条形区域变化率大于10
	for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++)
	{

		for (i = 0; i < lWidth - 140; i++)
		{
			lGrayChangeNumber = 0;
			// 对每一行用宽度为160的窗进行处理
			for(k=0;k<140;k++)
			{
				// 指向源图像倒数第j行,第i个象素的指针	
				lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i + k;
				lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i + k + 1;	
				pixelformer = (unsigned char)*lpSrcformer;
				pixellater  = (unsigned char)*lpSrclater;

				if (pixelformer != pixellater)
				{
					lGrayChangeNumber++;
				}

			}
			if (lGrayChangeNumber >= 10)
			{
				iLineNum[iLineNum1]=j;
				iLineNum1++;
				break;
			}
		}

	}

	if(iLineNum1<10)
	{
		AfxMessageBox("非车牌区域");
		pPlatePosi = &iPlatePosition[0];
		return 	pPlatePosi;
	}
	// 进一步确定行的位置,条件2:满足条件1的各行是否有10行是近似相邻的
	for(i=0;i<iLineNum1-1-10;i++)
	{

		for(j=0;j<10;j++)
		{
			if(abs(iLineNum[j+i+10]-iLineNum[j+i])<13)
			{
				iTopLine=iLineNum[j+i+10]+5;// 微调车牌上下界
				iLowLine = iTopLine -40;

			}
		}
	}
//		if (lGrayChangeNumber >= 10)
//		{
			// 判断前后满足条件的行是否是相邻
//			if((iLineLocation == j-1) || (iLineLocation == j-2))
//			{
//				iLineNumber++;
//			}
			// 记录满足条件的行的新位置
//			iLineLocation = j;
//		}
		
		// 确定满足条件的区域的上下边界
//		if((iLineNumber >=20) && (iLineNumber <=100))
//		{
//			iTopLine = iLineLocation+10;
//			iLowLine = iLineLocation - 30;
//			break;
//		}
//	}

	iLineLocation = 0;
	iLineNumber = 0;
	iLeftLine = 0;
	iRightLine = 0;

	iLineNum1 = 0;
	// 初步寻找满足条件的列,条件1:在一列内白色象素的数目大于5
	for (i = 0;i < lWidth ;i++)
	{
		lGrayChangeNumber = 0;
		for(j = iLowLine;j < iTopLine ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
//			lpSrclater  = (char *)lpDIBBits + lLineBytes * (j+1) + i ;	

			pixelformer = (unsigned char)*lpSrcformer;
//			pixellater  = (unsigned char)*lpSrclater;
			if (pixelformer == (BYTE)255)
			{
				lGrayChangeNumber++;
//				TRACE("%d\t",lGrayChangeNumber);
			}
		}
		if (lGrayChangeNumber >= 5)
		{
			iLineNum[iLineNum1]=i;
			iLineNum1++;
		}
	}

	if(iLineNum1<60)
	{
		AfxMessageBox("非车牌区域");
		pPlatePosi = &iPlatePosition[0];
		return 	pPlatePosi;
	}
	// 进一步确定列的位置,条件2:满足条件1的各列是否有80行是近似相邻的
	for(i=0;i<iLineNum1-1-40;i++)
	{
		int a1=0;
		for(j=0;j<40;j++)
		{
			if(abs(iLineNum[j+i+40]-iLineNum[j+i])<100)
			{
				iLeftLine=iLineNum[j+i] - 5;// 微调车牌左右界
				iRightLine = iLeftLine + 140;
				int q1=0;
				break;
			}
		}
		if(iLeftLine>0)
			break;
	}



	int q=0;
	for (j = iLowLine; j < iTopLine; j++)
	{
		for (i = iLeftLine; i < iRightLine; i++)
		{
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;	
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine);
			*lpDst = *lpSrc;
		}
	}
	

/*
	for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++)
	{
		lGrayChangeNumber = 0;
		for (i = 0; i < lWidth - 1; i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针	
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i +1;	
			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;

			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;

			}
		}
		// 记录满足条件的行的位置
		if (lGrayChangeNumber >= 10)
		{
			// 判断前后满足条件的行是否是相邻
			if((iLineLocation == j-1) || (iLineLocation == j-2))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = j;
		}
		
		// 确定满足条件的区域的上下边界
		if((iLineNumber >=20) && (iLineNumber <=100))
		{
			iTopLine = iLineLocation+10;
			iLowLine = iLineLocation - 30;
			break;
		}
	}

	iLineLocation = 0;
	iLineNumber = 0;
	iLeftLine = 0;
	iRightLine = 0;
	for (i = 0;i < lWidth ;i++)
	{
		lGrayChangeNumber = 0;
		for(j = iLowLine;j < iTopLine ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * (j+1) + i ;	

			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;
			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;
//				TRACE("%d\t",lGrayChangeNumber);
			}
		}
		if (lGrayChangeNumber >= 2)
		{
			// 判断前后满足条件的是否是相邻
			if((iLineLocation == i-1) && (iLineLocation >= i-20))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = i;
//			TRACE("%d\t",lGrayChangeNumber);
		}
		
		// 确定满足条件的区域的左右边界
		if((iLineNumber >=80) && (iLineNumber <=150))
		{
			iLeftLine = iLineLocation -90;
			iRightLine = iLeftLine + 140;
//			TRACE("%d\t",i);
			break;
		}		
	}

	int q=0;
	for (j = iLowLine; j < iTopLine; j++)
	{
		for (i = iLeftLine; i < iRightLine; i++)
		{
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;	
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine);
			*lpDst = *lpSrc;
		}
	}
*/	
//	for (j = 0; j < 40; j++)
//	{
//		for(i = 0; i < 140; i++)
//		{
//
//			lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i;
//			lpDst = (char *)lpDIBBits + lLineBytes * j + i;	
//			*lpDst = *lpSrc;
//		}
//	}

	// 传递车牌位置

    iPlatePosition[0] = 1;
	iPlatePosition[1] = iTopLine;
	iPlatePosition[2] = iLowLine;
	iPlatePosition[3] = iLeftLine;
	iPlatePosition[4] = iRightLine;

	pPlatePosi = &iPlatePosition[0];


	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return pPlatePosi;
}

/*************************************************************************
 *
 * 函数名称:
 *   RowScanDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行水平投影运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

int* RowscanDIB3(LPSTR lpDIBBits, LPSTR lpOrgDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine)
{
//	AfxMessageBox("Start...");
	
	// 指向源图像的指针
	LPSTR	lpSrc,lpSrcformer,lpSrclater;

	// 指向原始图像(汽车整车图像)
	LPSTR lpSrcOrg;

	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 分割后图像的宽度和高度
	LONG	lNewWidth = 140;
	LONG	lNewHeight = 40;

	//循环变量
	long i;
	long j;
	long k;

	// 获取车牌位置信息
	int *pPlatePosi;

	int iPlateLine[40];

	for(i=0;i<40;i++)
	{
		iPlateLine[i]=*pPlateLine;
		pPlateLine++;
	}

	// 图像中每行象素由 0->255 或 255->0 的次数
	long lGrayChangeNumber;

	// 前一个像素值
	unsigned char pixelformer;

	// 后一个像素值
	unsigned char pixellater;

	// 满足条件底行的位置
	int iLineLocation;

	// 连续出现变化次数超过阈值的行数
	int iLineNumber;

	// 满足条件的区域的上界 
	int iTopLine;

	// 满足条件的区域的下界 
	int iLowLine;

	// 满足条件的区域的左边界 
	int iLeftLine;

	// 满足条件的区域的右边界 
	int iRightLine;

	// 图像每行的字节数
	LONG lLineBytes;

	// 新图像每行的字节数
	LONG lNewLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	lNewLineBytes = WIDTHBYTES( lNewWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变

	// 标明是否找到车牌(第一个数),及车牌位置(后四个数)
    int iPlatePosition[5] = {0,0,0,0,0};

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lNewLineBytes * lNewHeight);

	iLineLocation = 0;
	iLineNumber = 0;
	iTopLine = 0;
	iLowLine = 0;

	// 记录满足条件的行的位置
	int iLineNum[100];
	for(i=0;i<100;i++)
	{
		iLineNum[i]=0;
	}
	int iLineNum1;
	iLineNum1 = 0;
	//int a1,a2,b1,b2;
	// 初步寻找满足条件的行,条件1:在一行内存在一连续的长度约为140的条形区域变化率大于10
	for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++)
	{

		for (i = 0; i < lWidth - 140; i++)
		{
			lGrayChangeNumber = 0;
			// 对每一行用宽度为160的窗进行处理
			for(k=0;k<140;k++)
			{
				// 指向源图像倒数第j行,第i个象素的指针	
				lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i + k;
				lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i + k + 1;	
				pixelformer = (unsigned char)*lpSrcformer;
				pixellater  = (unsigned char)*lpSrclater;

				if (pixelformer != pixellater)
				{
					lGrayChangeNumber++;
				}

			}
			if (lGrayChangeNumber >= 10)
			{
				iLineNum[iLineNum1]=j;
				iLineNum1++;
				break;
			}
		}

	}

	if(iLineNum1<10)
	{
		AfxMessageBox("非车牌区域");
		pPlatePosi = &iPlatePosition[0];
		return 	pPlatePosi;
	}
	// 进一步确定行的位置,条件2:满足条件1的各行是否有10行是近似相邻的
	for(i=0;i<iLineNum1-1-10;i++)
	{

		for(j=0;j<10;j++)
		{
			if(abs(iLineNum[j+i+10]-iLineNum[j+i])<13)
			{
				iTopLine=iLineNum[j+i+10]+5;// 微调车牌上下界
				iLowLine = iTopLine -40;

			}
		}
	}
//		if (lGrayChangeNumber >= 10)
//		{
			// 判断前后满足条件的行是否是相邻
//			if((iLineLocation == j-1) || (iLineLocation == j-2))
//			{
//				iLineNumber++;
//			}
			// 记录满足条件的行的新位置
//			iLineLocation = j;
//		}
		
		// 确定满足条件的区域的上下边界
//		if((iLineNumber >=20) && (iLineNumber <=100))
//		{
//			iTopLine = iLineLocation+10;
//			iLowLine = iLineLocation - 30;
//			break;
//		}
//	}

	iLineLocation = 0;
	iLineNumber = 0;
	iLeftLine = 0;
	iRightLine = 0;

	iLineNum1 = 0;
	// 初步寻找满足条件的列,条件1:在一列内白色象素的数目大于5
	for (i = 0;i < lWidth ;i++)
	{
		lGrayChangeNumber = 0;
		for(j = iLowLine;j < iTopLine ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
//			lpSrclater  = (char *)lpDIBBits + lLineBytes * (j+1) + i ;	

			pixelformer = (unsigned char)*lpSrcformer;
//			pixellater  = (unsigned char)*lpSrclater;
			if (pixelformer == (BYTE)255)
			{
				lGrayChangeNumber++;
//				TRACE("%d\t",lGrayChangeNumber);
			}
		}
		if (lGrayChangeNumber >= 5)
		{
			iLineNum[iLineNum1]=i;
			iLineNum1++;
		}
	}

	if(iLineNum1<60)
	{
		AfxMessageBox("非车牌区域");
		pPlatePosi = &iPlatePosition[0];
		return 	pPlatePosi;
	}
	// 进一步确定列的位置,条件2:满足条件1的各列是否有80行是近似相邻的
	for(i=0;i<iLineNum1-1-40;i++)
	{
		int a1=0;
		for(j=0;j<40;j++)
		{
			if(abs(iLineNum[j+i+40]-iLineNum[j+i])<100)
			{
				iLeftLine=iLineNum[j+i] - 5;// 微调车牌左右界
				iRightLine = iLeftLine + 140;
				int q1=0;
				break;
			}
		}
		if(iLeftLine>0)
			break;
	}



	int q=0;
	for (j = iLowLine; j < iTopLine; j++)
	{
		for (i = iLeftLine; i < iRightLine; i++)
		{
			lpSrc = (char *)lpOrgDIBBits + lLineBytes * j + i;	
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine);
			*lpDst = *lpSrc;
		}
	}
	

/*
	for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++)
	{
		lGrayChangeNumber = 0;
		for (i = 0; i < lWidth - 1; i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针	
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i +1;	
			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;

			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;

			}
		}
		// 记录满足条件的行的位置
		if (lGrayChangeNumber >= 10)
		{
			// 判断前后满足条件的行是否是相邻
			if((iLineLocation == j-1) || (iLineLocation == j-2))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = j;
		}
		
		// 确定满足条件的区域的上下边界
		if((iLineNumber >=20) && (iLineNumber <=100))
		{
			iTopLine = iLineLocation+10;
			iLowLine = iLineLocation - 30;
			break;
		}
	}

	iLineLocation = 0;
	iLineNumber = 0;
	iLeftLine = 0;
	iRightLine = 0;
	for (i = 0;i < lWidth ;i++)
	{
		lGrayChangeNumber = 0;
		for(j = iLowLine;j < iTopLine ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * (j+1) + i ;	

			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;
			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;
//				TRACE("%d\t",lGrayChangeNumber);
			}
		}
		if (lGrayChangeNumber >= 2)
		{
			// 判断前后满足条件的是否是相邻
			if((iLineLocation == i-1) && (iLineLocation >= i-20))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = i;
//			TRACE("%d\t",lGrayChangeNumber);
		}
		
		// 确定满足条件的区域的左右边界
		if((iLineNumber >=80) && (iLineNumber <=150))
		{
			iLeftLine = iLineLocation -90;
			iRightLine = iLeftLine + 140;
//			TRACE("%d\t",i);
			break;
		}		
	}

	int q=0;
	for (j = iLowLine; j < iTopLine; j++)
	{
		for (i = iLeftLine; i < iRightLine; i++)
		{
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;	
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine);
			*lpDst = *lpSrc;
		}
	}
*/	
//	for (j = 0; j < 40; j++)
//	{
//		for(i = 0; i < 140; i++)
//		{
//
//			lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i;
//			lpDst = (char *)lpDIBBits + lLineBytes * j + i;	
//			*lpDst = *lpSrc;
//		}
//	}

	// 传递车牌位置

    iPlatePosition[0] = 1;
	iPlatePosition[1] = iTopLine;
	iPlatePosition[2] = iLowLine;
	iPlatePosition[3] = iLeftLine;
	iPlatePosition[4] = iRightLine;

	pPlatePosi = &iPlatePosition[0];


	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return pPlatePosi;
}
/*************************************************************************
 *
 * 函数名称:
 *   RowScanDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行水平投影运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/
// 用于车牌区域归一化的处理
int* RowscanDIB4(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
//	AfxMessageBox("Start...");
	
	// 指向源图像的指针
	LPSTR	lpSrc,lpSrcformer,lpSrclater;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 获取车牌位置信息
	int *pPlatePosi;

	// 分割后图像的宽度和高度
	LONG	lNewWidth = 140;
	LONG	lNewHeight = 40;

	//循环变量
	long i;
	long j;

	// 图像中每行象素由 0->255 或 255->0 的次数
	long lGrayChangeNumber;

	// 前一个像素值
	unsigned char pixelformer;

	// 后一个像素值
	unsigned char pixellater;

	// 满足条件底行的位置
	int iLineLocation;

	// 连续出现变化次数超过阈值的行数
	int iLineNumber;

	// 满足条件的区域的上界 
	int iTopLine;

	// 满足条件的区域的下界 
	int iLowLine;

	// 满足条件的区域的左边界 
	int iLeftLine;

	// 满足条件的区域的右边界 
	int iRightLine;

	// 图像每行的字节数
	LONG lLineBytes;

	// 新图像每行的字节数
	LONG lNewLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	lNewLineBytes = WIDTHBYTES( lNewWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)0, lNewLineBytes * lNewHeight);

	iLineLocation = 0;
	iLineNumber = 0;
	iTopLine = 0;
	iLowLine = 0;

	for (j = 0; j < lHeight; j++)
	{
		lGrayChangeNumber = 0;
		for (i = 0; i < lWidth - 1; i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针	
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i +1;	
			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;

			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;

			}
		}
		// 记录满足条件的行的位置
		if (lGrayChangeNumber >= 10)
		{
			// 判断前后满足条件的行是否是相邻
			if(iLineLocation == j-1)//|| (iLineLocation == j-2))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = j;
		}
		
		// 确定满足条件的区域的上下边界
		if((lGrayChangeNumber == 0) && (iLineNumber > 15))
			break;
	}

	// iLineLocation和 iLineLocation-iLineNumber是准确上下界
	iLowLine = iLineLocation - iLineNumber - 3;
	iTopLine = iLowLine + iLineNumber + 6;


	iLeftLine = 0;
	iRightLine = 140;
/*	for (i = 0;i < lWidth ;i++)
	{
		lGrayChangeNumber = 0;
		for(j = iLowLine;j < iTopLine ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * (j+1) + i ;	

			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;
			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;
//				TRACE("%d\t",lGrayChangeNumber);
			}
		}
		if (lGrayChangeNumber >= 2)
		{
			// 判断前后满足条件的是否是相邻
			if((iLineLocation == i-1) && (iLineLocation >= i-20))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = i;
//			TRACE("%d\t",lGrayChangeNumber);
		}
		
		// 确定满足条件的区域的左右边界
		if((iLineNumber >=80) && (iLineNumber <=150))
		{
			iLeftLine = iLineLocation -90;
			iRightLine = iLeftLine + 140;
//			TRACE("%d\t",i);
			break;
		}		
	}
*/
	int q=0;
	for (j = iLowLine; j < iTopLine; j++)
	{
		for (i = iLeftLine; i < iRightLine; i++)
		{
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;	
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine);
			*lpDst = *lpSrc;
		}
	}
	
//	for (j = 0; j < 40; j++)
//	{
//		for(i = 0; i < 140; i++)
//		{
//
//			lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i;
//			lpDst = (char *)lpDIBBits + lLineBytes * j + i;	
//			*lpDst = *lpSrc;
//		}
//	}

	// 传递车牌位置
    int iPlatePosition[2] = {0,0};
	iPlatePosition[0] = iTopLine;
	iPlatePosition[1] = iLowLine;
//	iPlatePosition[2] = iLeftLine;
//	iPlatePosition[3] = iRightLine;

	pPlatePosi = &iPlatePosition[0];


	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
//	return TRUE;
	return pPlatePosi;
}


/*************************************************************************
 *
 * 函数名称:
 *   RowScanDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行水平投影运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

int* RowscanDIB1(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
//	AfxMessageBox("Start...");
	
	// 指向源图像的指针
	LPSTR	lpSrc,lpSrcformer,lpSrclater;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 获取车牌位置信息
	int *pPlatePosi;

	// 分割后图像的宽度和高度
	LONG	lNewWidth = 140;
	LONG	lNewHeight = 40;

	//循环变量
	long i;
	long j;

	// 图像中每行象素由 0->255 或 255->0 的次数
	long lGrayChangeNumber;

	// 前一个像素值
	unsigned char pixelformer;

	// 后一个像素值
	unsigned char pixellater;

	// 满足条件底行的位置
	int iLineLocation;

	// 连续出现变化次数超过阈值的行数
	int iLineNumber;

	// 满足条件的区域的上界 
	int iTopLine;

	// 满足条件的区域的下界 
	int iLowLine;

	// 满足条件的区域的左边界 
	int iLeftLine;

	// 满足条件的区域的右边界 
	int iRightLine;

	// 图像每行的字节数
	LONG lLineBytes;

	// 新图像每行的字节数
	LONG lNewLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	lNewLineBytes = WIDTHBYTES( lNewWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lNewLineBytes * lNewHeight);

	iLineLocation = 0;
	iLineNumber = 0;
	iTopLine = 0;
	iLowLine = 0;

	for (j = 0; j < lHeight; j++)
	{
		lGrayChangeNumber = 0;
		for (i = 0; i < lWidth - 1; i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针	
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i +1;	
			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;

			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;

			}
		}
		// 记录满足条件的行的位置
		if (lGrayChangeNumber >= 10)
		{
			// 判断前后满足条件的行是否是相邻
			if((iLineLocation == j-1) || (iLineLocation == j-2))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = j;
		}
		
		// 确定满足条件的区域的上下边界
		if((iLineNumber >=20) && (iLineNumber <=100))
		{
			iTopLine = iLineLocation+10;
			iLowLine = iLineLocation - 30;
			break;
		}
	}

	iLineLocation = 0;
	iLineNumber = 0;
	iLeftLine = 0;
	iRightLine = 0;
	for (i = 0;i < lWidth ;i++)
	{
		lGrayChangeNumber = 0;
		for(j = iLowLine;j < iTopLine ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * (j+1) + i ;	

			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;
			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;
//				TRACE("%d\t",lGrayChangeNumber);
			}
		}
		if (lGrayChangeNumber >= 2)
		{
			// 判断前后满足条件的是否是相邻
			if((iLineLocation == i-1) && (iLineLocation >= i-20))
			{
				iLineNumber++;
			}
			// 记录满足条件的行的新位置
			iLineLocation = i;
//			TRACE("%d\t",lGrayChangeNumber);
		}
		
		// 确定满足条件的区域的左右边界
		if((iLineNumber >=80) && (iLineNumber <=150))
		{
			iLeftLine = iLineLocation -90;
			iRightLine = iLeftLine + 140;
//			TRACE("%d\t",i);
			break;
		}		
	}

	int q=0;
	for (j = iLowLine; j < iTopLine; j++)
	{
		for (i = iLeftLine; i < iRightLine; i++)
		{
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;	
			lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine);
			*lpDst = *lpSrc;
		}
	}
	
//	for (j = 0; j < 40; j++)
//	{
//		for(i = 0; i < 140; i++)
//		{
//
//			lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i;
//			lpDst = (char *)lpDIBBits + lLineBytes * j + i;	
//			*lpDst = *lpSrc;
//		}
//	}

	// 传递车牌位置
    int iPlatePosition[4] = {0,0,0,0};
	iPlatePosition[0] = iTopLine;
	iPlatePosition[1] = iLowLine;
	iPlatePosition[2] = iLeftLine;
	iPlatePosition[3] = iRightLine;

	pPlatePosi = &iPlatePosition[0];


	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return pPlatePosi;
}

/*************************************************************************
 *
 * 函数名称:
 *   CharacterUnit()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   iWidht       - 归一化字符的宽度
 *   int   iHeight      - 归一化字符的高度
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对车牌字符图像进行归一化处理。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI CharacterUnit(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 指向缓存图像的指针
	unsigned char*	lpDst;
	
	// 指向缓存DIB图像的指针
	unsigned char*	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 分割后图像的宽度和高度
//	LONG	lNewWidth = 7 * 15;
//	LONG	lNewHeight = lHeight;

	//循环变量
	long i;
	long j;
	long lRow;
	long lLine;

	// 图像中每列灰度值为255的个数
	long lWhiteGrayNumber;

	// 像素的灰度值
	unsigned char pixelvalue;

	// 车牌字符所在的列的最左边位置
	int iCharLeftRow;

	// 车牌字符所在的列的最右边位置
	int iCharRightRow;

	// 标志位1,flag1=1时表示开始标志一个字符的位置
	int flag1;

	// 标志位2,flag2=1时表示找到一个字符
	int flag2;

	// 标志这是第几个字符
	int iCharNum;

	// 用于进行字符数据的复制
	int iCharLinePixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 新图像每行的字节数
	LONG lNewLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	lNewLineBytes = WIDTHBYTES( lWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lHeight); // 在此分配的内存的大小将来要改变

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (unsigned char* )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (unsigned char*)lpNewDIBBits;
	memset(lpDst, (BYTE)0, lNewLineBytes * lHeight);

	iCharLeftRow = 0;
	iCharRightRow = 0;
	flag1 = 1;
	flag2 = 0;
	iCharNum = 0;

	for (lRow = 0;lRow < lWidth ;lRow++)
	{
		lWhiteGrayNumber = 0;
		for(lLine = 0;lLine < lHeight ;lLine++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow;
			pixelvalue = (unsigned char)*lpSrc;

			if (pixelvalue == 255)
			{
				lWhiteGrayNumber++;
//				TRACE("%d\t",lWhiteGrayNumber);
			}
		}

		// 寻找字符左边起始列
		if ((lWhiteGrayNumber >= 2)&&(flag1 == 1))
		{
			flag1 = 0;
			iCharLeftRow = lRow;
		}

		// 寻找字符右边的终止列
		if ((lWhiteGrayNumber <= 2)&&(flag1 == 0))
		{
			iCharRightRow = lRow;
			flag1 = 1;
			flag2 = 1;
		}
		
		// 找到一个字符,复制
		if(((iCharRightRow - iCharLeftRow) > 7)&&(flag2 == 1))
		{
			iCharNum++;

			for (j = 0; j < lHeight; j++)
			{
				iCharLinePixel = 0;
				for (i = iCharLeftRow - 1; i < iCharRightRow + 1; i++)
				{

					lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;	
//					lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + i;//20 * (iCharNum - 1) + a;
					lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + (int)(lWidth / 7) * (iCharNum - 1) + iCharLinePixel;
//					*lpDst = (unsigned char)255;
					*lpDst = *lpSrc;
					iCharLinePixel++;
				}
			}
			flag2 = 0;
		}

		if(iCharNum == 7)
		{
			break;
		}

	}

	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	return TRUE;

}

/*************************************************************************
 *
 * 函数名称:
 *   CharacterUnit()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   int   iWidht       - 归一化字符的宽度
 *   int   iHeight      - 归一化字符的高度
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对车牌字符图像进行归一化处理。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI CharacterUnit1(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int iWidth, int iHeight)
{
/*	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 指向缓存图像的指针
	unsigned char*	lpDst;
	
	// 指向缓存DIB图像的指针
	unsigned char*	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 分割后图像的宽度和高度
//	LONG	lNewWidth = 7 * 15;
//	LONG	lNewHeight = lHeight;

	//循环变量
	long i;
	long j;
	long lRow;
	long lLine;

	// 图像中每行灰度值为255的个数
	long lWhiteGrayNumber;

	// 像素的灰度值
	unsigned char pixelvalue;

	// 车牌字符所在行的最下边位置
	int iCharTopRow;

	// 车牌字符所在的行的最上边位置
	int iCharLowRow;

	// 标志位1,flag1=1时表示开始标志一个字符的位置
	int flag1;

	// 标志位2,flag2=1时表示找到一个字符
	int flag2;

	// 标志这是第几个字符
	int iCharNum;

	// 用于进行字符数据的复制
	int iCharLinePixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 新图像每行的字节数
	LONG lNewLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	lNewLineBytes = WIDTHBYTES( lWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lHeight); // 在此分配的内存的大小将来要改变

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (unsigned char* )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (unsigned char*)lpNewDIBBits;
	memset(lpDst, (BYTE)0, lNewLineBytes * lHeight);

	iCharLeftRow = 0;
	iCharRightRow = 0;
	flag1 = 1;
	flag2 = 0;
	iCharNum = 0;

	for (lRow = 0;lRow < lWidth ;lRow++)
	{
		lWhiteGrayNumber = 0;
		for(lLine = 0;lLine < lHeight ;lLine++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow;
			pixelvalue = (unsigned char)*lpSrc;

			if (pixelvalue == 255)
			{
				lWhiteGrayNumber++;
//				TRACE("%d\t",lWhiteGrayNumber);
			}
		}

		// 寻找字符左边起始列
		if ((lWhiteGrayNumber >= 2)&&(flag1 == 1))
		{
			flag1 = 0;
			iCharLeftRow = lRow;
		}

		// 寻找字符右边的终止列
		if ((lWhiteGrayNumber <= 2)&&(flag1 == 0))
		{
			iCharRightRow = lRow;
			flag1 = 1;
			flag2 = 1;
		}
		
		// 找到一个字符,复制
		if(((iCharRightRow - iCharLeftRow) > 7)&&(flag2 == 1))
		{
			iCharNum++;

			for (j = 0; j < lHeight; j++)
			{
				iCharLinePixel = 0;
				for (i = iCharLeftRow - 1; i < iCharRightRow + 1; i++)
				{

					lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;	
//					lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + i;//20 * (iCharNum - 1) + a;
					lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + (int)(lWidth / 7) * (iCharNum - 1) + iCharLinePixel;
//					*lpDst = (unsigned char)255;
					*lpDst = *lpSrc;
					iCharLinePixel++;
				}
			}
			flag2 = 0;
		}

		if(iCharNum == 7)
		{
			break;
		}

	}

	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);
*/
	return TRUE;

}

BOOL WINAPI BPTrain(int	iInputNum, int iMidNum, int iOutputNum)
{

	// 输入层、中间层和输出层的结点数
	// 输入层至隐层的权值
	double fHidWeight[64][16];
	// 隐层至输出层的权值
	double fOutWeight[16][10];
	// 存储输入数据
	int iTranData[10][64];
	// 存储隐层的输入状态
	double fHidTemp[16];
	// 存储隐层的输出
	double fHidData[16];
	// 存储输出层的输入状态
	double fOutTemp[10];
	// 存储输出层的输出
	double fOutData[10];
	// 输出层至隐层的回传误差
	double fOutError[10];
	// 隐层至输入层的回传误差
	double fHidError[16];
	// 每一次对10个数字进行训练得到的误差
	double fNumError[10][3];
	// 输出层教师的取值
	double fTeacher[10][10];
	// 训练的步长
	double fStep = 0.2;
	// 对某个样本训练结束标志符
	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
	bool   bAllEnd = FALSE;
	// 识别结果
//	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值.dat";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值.dat";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比
//	int iNoise;
	// 存储加入噪声以后的识别数据
	int iNoiseData[10][64];
	// 用于情况的选择
//	int iChoise;


	// BP网络的初始化

    // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效
//	srand((unsigned)time( NULL ) );
	// 输入层至隐层的权值的初始化(0 - 0.1)
	for(i = 0; i < 64; i++)
	{
		for(j = 0; j < 16; j++)
		{
			fHidWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 隐层至输出层的权值的初始化
	for(i = 0; i < 16; i++)
	{
		for(j = 0; j <10; j++)
		{
			fOutWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 教师向量的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
			if(j==i)
				fTeacher[i][j] = 1.0;
			else
				fTeacher[i][j] = 0.0;
		}
	}

	///////////////////////////////////////////////////////
	// 训练

	////// 读入训练数据 //////
	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 64; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%d",&iTranData[i][j]);
			iNoiseData[i][j] = iTranData[i][j];
		}
	}
	// 关闭文件
	fclose(fpTranData);
//	cout<<" 结束!";

//	AfxMessageBox("\n  第二步:用误差回传算法进行学习。正在进行......");
	// 用误差回传算法进行学习
	do
	{
		// 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字
		for(iTranNum = 0; iTranNum < 10; iTranNum++)
		{
			do
			{
				bSingleEnd = FALSE;
				icount++;

				// 计算隐层各结点的值			
				for(i = 0; i < 16; i++)		// i代表隐层的各个结点
				{
					fHidTemp[i] = 0.0;					
					for(j = 0; j < 64; j++)	// j代表输入层的各个结点
					{
						fHidTemp[i] += fHidWeight[j][i] * (double)iTranData[iTranNum][j]; // ??????
					}
					// 根据传递函数公式求得隐层的输出
					fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
				}

				// 计算输出层各结点的值			
				for(i = 0; i < 10; i++)		// i代表输出层的各个结点
				{
					fOutTemp[i] = 0.0;					
					for(j = 0; j < 16; j++)	// j代表隐层的各个结点
					{
						fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
					}
					// 根据传递函数公式求得输出层的输出
					fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
				}
				// 计算误差,判断是否结束此样本的训练
				fNumError[iTranNum][0] = 0.0;
				for(i = 0; i < 10; i++)
				{
					fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0;
				}

				fNumError[iTranNum][1] = fOutWeight[0][0];

				if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效
    			   && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) )
					bSingleEnd = TRUE;

				// 实现误差回传					
				else
				{
					// 计算输出层至隐层的回传误差
					for(i = 0; i < 10; i++)
					{
						fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i])
									  * fOutData[i] * (1.0 - fOutData[i]);	
					}
					// 计算隐层至输入层的回传误差
					for(i = 0; i < 16; i++)
					{
						fHidError[i] = 0.0;
						for(j = 0; j < 10; j++)
						{
							fHidError[i] += fOutError[j] * fOutWeight[i][j]
										   * fHidData[i] * (1.0 - fHidData[i]);
						}
					}
					// 计算隐层至输出层经误差回传修正后新的权值
					for(i = 0; i < 16; i++)
					{
						for(j = 0;j < 10; j++)
						{
							fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i];
						}
					}
					// 计算输入层至隐层的权值
					for(i = 0; i < 64; i++)
					{
						for(j = 0; j < 16; j++)
						{
							fHidWeight[i][j] += fStep * fHidError[j] * iTranData[iTranNum][i];
						}
					}

				}

			}while(bSingleEnd == FALSE);
			
		}
		// 用于判断用同一组权值对10个数字进行训练是否都满足条件
		int a = 0;
		for(i = 0; i < 9; i++)
		{
			if(fNumError[i][1] == fNumError[i+1][1]) 
				a++;
		}
		if(a==9)
			bAllEnd = TRUE;
		else
			bAllEnd = FALSE;
	}while(bAllEnd == FALSE);
//	AfxMessageBox("训练终于结束了!");


	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 64; i++)
	{
		for(j = 0; j < 16; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpHidWeight,"%10f",fHidWeight[i][j]);
		}
		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f",fOutWeight[i][j]);
			fprintf(fpOutWeight,"%10f",fOutWeight[i][j]);
		}
		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	return TRUE;
}

BOOL WINAPI BPTrain13Section(int iInputNum, int iMidNum, int iOutputNum)
{

	// 输入层、中间层和输出层的结点数
	// 输入层至隐层的权值
	double fHidWeight[13][10];
	// 隐层至输出层的权值
	double fOutWeight[10][10];
	// 存储输入数据
	float fTranData[10][13];
	// 存储隐层的输入状态
	double fHidTemp[10];
	// 存储隐层的输出
	double fHidData[10];
	// 存储输出层的输入状态
	double fOutTemp[10];
	// 存储输出层的输出
	double fOutData[10];
	// 输出层至隐层的回传误差
	double fOutError[10];
	// 隐层至输入层的回传误差
	double fHidError[10];
	// 每一次对10个数字进行训练得到的误差
	double fNumError[10][3];
	// 输出层教师的取值
	double fTeacher[10][10];
	// 训练的步长
	double fStep = 0.2;
	// 对某个样本训练结束标志符
	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
	bool   bAllEnd = FALSE;
	// 识别结果
//	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据_13段.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_13段.txt";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_13段.txt";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比

	// BP网络的初始化

    // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效
//	srand((unsigned)time( NULL ) );
	// 输入层至隐层的权值的初始化(0 - 0.1)
	for(i = 0; i < 13; i++)
	{
		for(j = 0; j < 10; j++)
		{
			fHidWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 隐层至输出层的权值的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j <10; j++)
		{
			fOutWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 教师向量的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
			if(j==i)
				fTeacher[i][j] = 1.0;
			else
				fTeacher[i][j] = 0.0;
		}
	}
    int q=0;
	///////////////////////////////////////////////////////
	// 训练

	////// 读入训练数据 //////
	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 13; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%f",&fTranData[i][j]);
		}
	}
	// 关闭文件
	fclose(fpTranData);
//	cout<<" 结束!";

//	AfxMessageBox("\n  第二步:用误差回传算法进行学习。正在进行......");
	// 用误差回传算法进行学习
	do
	{
		// 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字
		for(iTranNum = 0; iTranNum < 10; iTranNum++)
		{
			do
			{
				bSingleEnd = FALSE;
				icount++;

				// 计算隐层各结点的值			
				for(i = 0; i < 10; i++)		// i代表隐层的各个结点
				{
					fHidTemp[i] = 0.0;					
					for(j = 0; j < 13; j++)	// j代表输入层的各个结点
					{
						fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ??????
					}
					// 根据传递函数公式求得隐层的输出
					fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
				}

				// 计算输出层各结点的值			
				for(i = 0; i < 10; i++)		// i代表输出层的各个结点
				{
					fOutTemp[i] = 0.0;					
					for(j = 0; j < 10; j++)	// j代表隐层的各个结点
					{
						fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
					}
					// 根据传递函数公式求得输出层的输出
					fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
				}
				// 计算误差,判断是否结束此样本的训练
				fNumError[iTranNum][0] = 0.0;
				for(i = 0; i < 10; i++)
				{
					fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0;
				}

				fNumError[iTranNum][1] = fOutWeight[0][0];

				if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效
    			   && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) )
					bSingleEnd = TRUE;

				// 实现误差回传					
				else
				{
					// 计算输出层至隐层的回传误差
					for(i = 0; i < 10; i++)
					{
						fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i])
									  * fOutData[i] * (1.0 - fOutData[i]);	
					}
					// 计算隐层至输入层的回传误差
					for(i = 0; i < 10; i++)
					{
						fHidError[i] = 0.0;
						for(j = 0; j < 10; j++)
						{
							fHidError[i] += fOutError[j] * fOutWeight[i][j]
										   * fHidData[i] * (1.0 - fHidData[i]);
						}
					}
					// 计算隐层至输出层经误差回传修正后新的权值
					for(i = 0; i < 10; i++)
					{
						for(j = 0;j < 10; j++)
						{
							fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i];
						}
					}
					// 计算输入层至隐层的权值
					for(i = 0; i <13; i++)
					{
						for(j = 0; j < 10; j++)
						{
							fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i];
						}
					}

				}

			}while(bSingleEnd == FALSE);
			
		}
		// 用于判断用同一组权值对10个数字进行训练是否都满足条件
		int a = 0;
		for(i = 0; i < 9; i++)
		{
			if(fNumError[i][1] == fNumError[i+1][1]) 
				a++;
		}
		float z1=fNumError[0][1] - fNumError[9][1];
		if(a==9)
			bAllEnd = TRUE;
		else
			bAllEnd = FALSE;
		int z2=0;
	}while(bAllEnd == FALSE);
	AfxMessageBox("训练终于结束了!");


	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 13; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpHidWeight,"%10f",fHidWeight[i][j]);
		}
		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f",fOutWeight[i][j]);
			fprintf(fpOutWeight,"%10f",fOutWeight[i][j]);
		}
		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	return TRUE;
}


BOOL WINAPI BPTrain16SectionLetter(int iInputNum, int iMidNum, int iOutputNum)
{

	// 输入层、中间层和输出层的结点数
	// 输入层至隐层的权值
	double fHidWeight[16][10];
	// 隐层至输出层的权值
	double fOutWeight[10][26];
	// 存储输入数据
	float fTranData[26][16];
	// 存储隐层的输入状态
	double fHidTemp[10];
	// 存储隐层的输出
	double fHidData[10];
	// 存储输出层的输入状态
	double fOutTemp[26];
	// 存储输出层的输出
	double fOutData[26];
	// 输出层至隐层的回传误差
	double fOutError[26];
	// 隐层至输入层的回传误差
	double fHidError[10];
	// 每一次对10个数字进行训练得到的误差
	double fNumError[26][3];
	// 输出层教师的取值
	double fTeacher[26][26];
	// 训练的步长
	double fStep = 0.2;
	// 对某个样本训练结束标志符
	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
	bool   bAllEnd = FALSE;
	// 识别结果
//	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据_16段投影字母.txt ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_16段投影字母.txt ";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_16段投影字母.txt ";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比

	// BP网络的初始化

    // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效
//	srand((unsigned)time( NULL ) );
	// 输入层至隐层的权值的初始化(0 - 0.1)
	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
			fHidWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 隐层至输出层的权值的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j <26; j++)
		{
			fOutWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 教师向量的初始化
	for(i = 0; i < 26; i++)
	{
		for(j = 0; j < 26; j++)
		{
			if(j==i)
				fTeacher[i][j] = 1.0;
			else
				fTeacher[i][j] = 0.0;
		}
	}
    int q=0;
	///////////////////////////////////////////////////////
	// 训练

	////// 读入训练数据 //////
	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 26; i++)
	{
		for(j = 0; j < 16; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%f",&fTranData[i][j]);
		}
	}
	// 关闭文件
	fclose(fpTranData);
//	cout<<" 结束!";

//	AfxMessageBox("\n  第二步:用误差回传算法进行学习。正在进行......");
	// 用误差回传算法进行学习
	do
	{
		// 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字
		for(iTranNum = 0; iTranNum < 26; iTranNum++)
		{
			do
			{
				bSingleEnd = FALSE;
				icount++;

				// 计算隐层各结点的值			
				for(i = 0; i < 10; i++)		// i代表隐层的各个结点
				{
					fHidTemp[i] = 0.0;					
					for(j = 0; j < 16; j++)	// j代表输入层的各个结点
					{
						fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ??????
					}
					// 根据传递函数公式求得隐层的输出
					fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
				}

				// 计算输出层各结点的值			
				for(i = 0; i < 26; i++)		// i代表输出层的各个结点
				{
					fOutTemp[i] = 0.0;					
					for(j = 0; j < 10; j++)	// j代表隐层的各个结点
					{
						fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
					}
					// 根据传递函数公式求得输出层的输出
					fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
				}
				// 计算误差,判断是否结束此样本的训练
				fNumError[iTranNum][0] = 0.0;
				for(i = 0; i < 26; i++)
				{
					fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0;
				}

				fNumError[iTranNum][1] = fOutWeight[0][0];

				if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效
    			   && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) )
					bSingleEnd = TRUE;

				// 实现误差回传					
				else
				{
					// 计算输出层至隐层的回传误差
					for(i = 0; i < 26; i++)
					{
						fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i])
									  * fOutData[i] * (1.0 - fOutData[i]);	
					}
					// 计算隐层至输入层的回传误差
					for(i = 0; i < 10; i++)
					{
						fHidError[i] = 0.0;
						for(j = 0; j < 26; j++)
						{
							fHidError[i] += fOutError[j] * fOutWeight[i][j]
										   * fHidData[i] * (1.0 - fHidData[i]);
						}
					}
					// 计算隐层至输出层经误差回传修正后新的权值
					for(i = 0; i < 10; i++)
					{
						for(j = 0;j < 26; j++)
						{
							fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i];
						}
					}
					// 计算输入层至隐层的权值
					for(i = 0; i <16; i++)
					{
						for(j = 0; j < 10; j++)
						{
							fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i];
						}
					}

				}

			}while(bSingleEnd == FALSE);
			
		}
		// 用于判断用同一组权值对10个数字进行训练是否都满足条件
		int a = 0;
		for(i = 0; i < 25; i++)
		{
			if(fNumError[i][1] == fNumError[i+1][1]) 
				a++;
		}
		float zzz=fNumError[0][1]-fNumError[25][1];
		if(a==25)
			bAllEnd = TRUE;
		else
			bAllEnd = FALSE;
		int zz=0;
	}while(bAllEnd == FALSE);
	AfxMessageBox("训练终于结束了!");


	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"w+"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpHidWeight,"%10f",fHidWeight[i][j]);
		}
		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"w+"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 26; j++)
		{
//			fprintf(fpOutWeight,"%f",fOutWeight[i][j]);
			fprintf(fpOutWeight,"%10f",fOutWeight[i][j]);
		}
		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	return TRUE;
}


BOOL WINAPI BPTrain16SectionNumber(int iInputNum, int iMidNum, int iOutputNum)
{


	// 输入层、中间层和输出层的结点数
	// 输入层至隐层的权值
	double fHidWeight[16][10];
	// 隐层至输出层的权值
	double fOutWeight[10][10];
	// 存储输入数据
	float fTranData[10][16];//float fTranData[100][16],每个数字有10个训练样本
	// 存储隐层的输入状态
	double fHidTemp[10];
	// 存储隐层的输出
	double fHidData[10];
	// 存储输出层的输入状态
	double fOutTemp[10];
	// 存储输出层的输出
	double fOutData[10];
	// 输出层至隐层的回传误差
	double fOutError[10];
	// 隐层至输入层的回传误差
	double fHidError[10];
	// 每一次对10个数字进行训练得到的误差
	double fNumError[10][3];//double fNumError[100][3];
	// 输出层教师的取值
	double fTeacher[10][10];//
	// 训练的步长
	double fStep = 0.2;
	// 对某个样本训练结束标志符
	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
	bool   bAllEnd = FALSE;
	// 识别结果
//	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据_16段投影数字.txt ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_16段投影数字.txt";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_16段投影数字.txt";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数据
	int iTranNum;
	// 正在训练或识别的数字
//	int iTranNumber;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比

	// BP网络的初始化

    // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效
//	srand((unsigned)time( NULL ) );
	// 输入层至隐层的权值的初始化(0 - 0.1)
	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
			fHidWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 隐层至输出层的权值的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j <10; j++)
		{
			fOutWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 教师向量的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
			if(j==i)
				fTeacher[i][j] = 1.0;
			else
				fTeacher[i][j] = 0.0;
		}
	}
    int q=0;
	///////////////////////////////////////////////////////
	// 训练

	////// 读入训练数据 //////
	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)//for(i = 0; i < 100; i++)
	{
		for(j = 0; j < 16; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%f",&fTranData[i][j]);
		}
	}
	// 关闭文件
	fclose(fpTranData);
//	cout<<" 结束!";

//	AfxMessageBox("\n  第二步:用误差回传算法进行学习。正在进行......");
	// 用误差回传算法进行学习
	do
	{
		// 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字
		for(iTranNum = 0; iTranNum < 10; iTranNum++)//for(iTranNum = 0; iTranNum < 100; iTranNum++)
		{											
			int z=0;
			do
			{
				bSingleEnd = FALSE;
				icount++;

				// 计算隐层各结点的值			
				for(i = 0; i < 10; i++)		// i代表隐层的各个结点
				{
					fHidTemp[i] = 0.0;					
					for(j = 0; j < 16; j++)	// j代表输入层的各个结点
					{
						fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ??????
					}
					// 根据传递函数公式求得隐层的输出
					fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
				}

				// 计算输出层各结点的值			
				for(i = 0; i < 10; i++)		// i代表输出层的各个结点
				{
					fOutTemp[i] = 0.0;					
					for(j = 0; j < 10; j++)	// j代表隐层的各个结点
					{
						fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
					}
					// 根据传递函数公式求得输出层的输出
					fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
				}
				// 计算误差,判断是否结束此样本的训练
				fNumError[iTranNum][0] = 0.0;
				for(i = 0; i < 10; i++)
				{
					fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0;
				}

				fNumError[iTranNum][1] = fOutWeight[0][0];

				if((fNumError[iTranNum][0] < 0.1)// 如您想提高训练的效果,请下行注释有效
    			   && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) )
					bSingleEnd = TRUE;

				// 实现误差回传					
				else
				{
					// 计算输出层至隐层的回传误差
					for(i = 0; i < 10; i++)
					{
						fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i])
									  * fOutData[i] * (1.0 - fOutData[i]);	
					}
					// 计算隐层至输入层的回传误差
					for(i = 0; i < 10; i++)
					{
						fHidError[i] = 0.0;
						for(j = 0; j < 10; j++)
						{
							fHidError[i] += fOutError[j] * fOutWeight[i][j]
										   * fHidData[i] * (1.0 - fHidData[i]);
						}
					}
					// 计算隐层至输出层经误差回传修正后新的权值
					for(i = 0; i < 10; i++)
					{
						for(j = 0;j < 10; j++)
						{
							fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i];
						}
					}
					// 计算输入层至隐层的权值
					for(i = 0; i <16; i++)
					{
						for(j = 0; j < 10; j++)
						{
							fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i];
						}
					}

				}

			}while(bSingleEnd == FALSE);
			
		}
		// 用于判断用同一组权值对10个数字进行训练是否都满足条件
		int a = 0;
		for(i = 0; i < 9; i++)//for(i = 0; i < 99; i++)
		{
			if(fNumError[i][1] == fNumError[i+1][1]) 
				a++;
		}
		float za=fNumError[0][1] - fNumError[9][1];
		if(a==9)//if(a==99)
			bAllEnd = TRUE;
		else
			bAllEnd = FALSE;
	}while(bAllEnd == FALSE);
	AfxMessageBox("训练终于结束了!");


	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpHidWeight,"%10f",fHidWeight[i][j]);
		}
		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f",fOutWeight[i][j]);
			fprintf(fpOutWeight,"%10f",fOutWeight[i][j]);
		}
		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	return TRUE;
}

BOOL WINAPI BPTrain16SectionNumber2(int iInputNum, int iMidNum, int iOutputNum)
{
//#define TRAINDATANUM 100 // 用于训练的数字样本的个数,应为10的整数倍
//#define TRAINDATALET 260 // 用于训练的字母样本的个数,应为26的整数倍


	// 输入层、中间层和输出层的结点数
	// 输入层至隐层的权值
	double fHidWeight[16][10];
	// 隐层至输出层的权值
	double fOutWeight[10][10];
	// 存储输入数据
	float fTranData[TRAINDATANUM][16];//float fTranData[100][16],每个数字有10个训练样本
	// 存储隐层的输入状态
	double fHidTemp[10];
	// 存储隐层的输出
	double fHidData[10];
	// 存储输出层的输入状态
	double fOutTemp[10];
	// 存储输出层的输出
	double fOutData[10];
	// 输出层至隐层的回传误差
	double fOutError[10];
	// 隐层至输入层的回传误差
	double fHidError[10];
	// 每一次对10个数字进行训练得到的误差
	double fNumError[TRAINDATANUM][3];//double fNumError[100][3];
	// 输出层教师的取值
	double fTeacher[10][10];//
	// 训练的步长
	double fStep = 0.2;
	// 对某个样本训练结束标志符
	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
	bool   bAllEnd = FALSE;
	// 识别结果
//	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据_16段投影数字.txt ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_16段投影数字.txt";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_16段投影数字.txt";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数据
	int iTranNum;
	// 正在训练或识别的数字
	int iTranNumber;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比

	// BP网络的初始化

    // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效
//	srand((unsigned)time( NULL ) );
	// 输入层至隐层的权值的初始化(0 - 0.1)
	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
			fHidWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 隐层至输出层的权值的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j <10; j++)
		{
			fOutWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 教师向量的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
			if(j==i)
				fTeacher[i][j] = 1.0;
			else
				fTeacher[i][j] = 0.0;
		}
	}
    int q=0;
	///////////////////////////////////////////////////////
	// 训练

	////// 读入训练数据 //////
	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < TRAINDATANUM; i++)//for(i = 0; i < 100; i++)
	{
		for(j = 0; j < 16; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%f",&fTranData[i][j]);
		}
	}
	// 关闭文件
	fclose(fpTranData);
//	cout<<" 结束!";

//	AfxMessageBox("\n  第二步:用误差回传算法进行学习。正在进行......");
	// 用误差回传算法进行学习
	do
	{
		// 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字
		for(iTranNum = 0; iTranNum < TRAINDATANUM; iTranNum++)//for(iTranNum = 0; iTranNum < 100; iTranNum++)
		{											
			iTranNumber=iTranNum/10;
			int z=0;
			do
			{
				bSingleEnd = FALSE;
				icount++;

				// 计算隐层各结点的值			
				for(i = 0; i < 10; i++)		// i代表隐层的各个结点
				{
					fHidTemp[i] = 0.0;					
					for(j = 0; j < 16; j++)	// j代表输入层的各个结点
					{
						fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ??????
					}
					// 根据传递函数公式求得隐层的输出
					fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
				}

				// 计算输出层各结点的值			
				for(i = 0; i < 10; i++)		// i代表输出层的各个结点
				{
					fOutTemp[i] = 0.0;					
					for(j = 0; j < 10; j++)	// j代表隐层的各个结点
					{
						fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
					}
					// 根据传递函数公式求得输出层的输出
					fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
				}
				// 计算误差,判断是否结束此样本的训练
				fNumError[iTranNum][0] = 0.0;
				for(i = 0; i < 10; i++)
				{
					fNumError[iTranNum][0] += ( (fTeacher[iTranNumber][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0;
				}

				fNumError[iTranNum][1] = fOutWeight[0][0];

				if((fNumError[iTranNum][0] < 0.1)// 如您想提高训练的效果,请下行注释有效
    			   && ( (fOutData[iTranNumber] - 1.0) * (fOutData[iTranNumber] - 1.0) < 0.01 ) )
					bSingleEnd = TRUE;

				// 实现误差回传					
				else
				{
					// 计算输出层至隐层的回传误差
					for(i = 0; i < 10; i++)
					{
						fOutError[i] = (fTeacher[iTranNumber][i]-fOutData[i])
									  * fOutData[i] * (1.0 - fOutData[i]);	
					}
					// 计算隐层至输入层的回传误差
					for(i = 0; i < 10; i++)
					{
						fHidError[i] = 0.0;
						for(j = 0; j < 10; j++)
						{
							fHidError[i] += fOutError[j] * fOutWeight[i][j]
										   * fHidData[i] * (1.0 - fHidData[i]);
						}
					}
					// 计算隐层至输出层经误差回传修正后新的权值
					for(i = 0; i < 10; i++)
					{
						for(j = 0;j < 10; j++)
						{
							fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i];
						}
					}
					// 计算输入层至隐层的权值
					for(i = 0; i <16; i++)
					{
						for(j = 0; j < 10; j++)
						{
							fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i];
						}
					}

				}

			}while(bSingleEnd == FALSE);
			
		}
		// 用于判断用同一组权值对10个数字进行训练是否都满足条件
		int a = 0;
		for(i = 0; i < TRAINDATANUM-1; i++)//for(i = 0; i < 99; i++)
		{
			if(fNumError[i][1] == fNumError[i+1][1]) 
				a++;
		}
		if(a==TRAINDATANUM-1)//if(a==99)
			bAllEnd = TRUE;
		else
			bAllEnd = FALSE;
	}while(bAllEnd == FALSE);
	AfxMessageBox("训练终于结束了!");


	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpHidWeight,"%10f",fHidWeight[i][j]);
		}
		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f",fOutWeight[i][j]);
			fprintf(fpOutWeight,"%10f",fOutWeight[i][j]);
		}
		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	return TRUE;
}


BOOL WINAPI BPTrainStruct(int iInputNum, int iMidNum, int iOutputNum)
{

	// 输入层、中间层和输出层的结点数
	// 输入层至隐层的权值
	double fHidWeight[16][10];
	// 隐层至输出层的权值
	double fOutWeight[10][10];
	// 存储输入数据
	float fTranData[10][16];
	// 存储隐层的输入状态
	double fHidTemp[10];
	// 存储隐层的输出
	double fHidData[10];
	// 存储输出层的输入状态
	double fOutTemp[10];
	// 存储输出层的输出
	double fOutData[10];
	// 输出层至隐层的回传误差
	double fOutError[10];
	// 隐层至输入层的回传误差
	double fHidError[10];
	// 每一次对10个数字进行训练得到的误差
	double fNumError[10][3];
	// 输出层教师的取值
	double fTeacher[10][10];
	// 训练的步长
	double fStep = 0.2;
	// 对某个样本训练结束标志符
	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
	bool   bAllEnd = FALSE;
	// 识别结果
//	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据_微特征.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_微特征.dat";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_微特征.dat";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比

	// BP网络的初始化

    // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效
//	srand((unsigned)time( NULL ) );
	// 输入层至隐层的权值的初始化(0 - 0.1)
	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
			fHidWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 隐层至输出层的权值的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j <10; j++)
		{
			fOutWeight[i][j] = (double) (rand() / 327670.0);
		}
	}
	// 教师向量的初始化
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
			if(j==i)
				fTeacher[i][j] = 1.0;
			else
				fTeacher[i][j] = 0.0;
		}
	}
    int q=0;
	///////////////////////////////////////////////////////
	// 训练

	////// 读入训练数据 //////
	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 16; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%f",&fTranData[i][j]);
		}
	}
	// 关闭文件
	fclose(fpTranData);
//	cout<<" 结束!";

//	AfxMessageBox("\n  第二步:用误差回传算法进行学习。正在进行......");
	// 用误差回传算法进行学习
	do
	{
		// 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字
		for(iTranNum = 0; iTranNum < 10; iTranNum++)
		{
			do
			{
				bSingleEnd = FALSE;
				icount++;

				// 计算隐层各结点的值			
				for(i = 0; i < 10; i++)		// i代表隐层的各个结点
				{
					fHidTemp[i] = 0.0;					
					for(j = 0; j < 16; j++)	// j代表输入层的各个结点
					{
						fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ??????
					}
					// 根据传递函数公式求得隐层的输出
					fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
				}

				// 计算输出层各结点的值			
				for(i = 0; i < 10; i++)		// i代表输出层的各个结点
				{
					fOutTemp[i] = 0.0;					
					for(j = 0; j < 10; j++)	// j代表隐层的各个结点
					{
						fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
					}
					// 根据传递函数公式求得输出层的输出
					fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
				}
				// 计算误差,判断是否结束此样本的训练
				fNumError[iTranNum][0] = 0.0;
				for(i = 0; i < 10; i++)
				{
					fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0;
				}

				fNumError[iTranNum][1] = fOutWeight[0][0];

				if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效
    			   && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) )
					bSingleEnd = TRUE;

				// 实现误差回传					
				else
				{
					// 计算输出层至隐层的回传误差
					for(i = 0; i < 10; i++)
					{
						fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i])
									  * fOutData[i] * (1.0 - fOutData[i]);	
					}
					// 计算隐层至输入层的回传误差
					for(i = 0; i < 10; i++)
					{
						fHidError[i] = 0.0;
						for(j = 0; j < 10; j++)
						{
							fHidError[i] += fOutError[j] * fOutWeight[i][j]
										   * fHidData[i] * (1.0 - fHidData[i]);
						}
					}
					// 计算隐层至输出层经误差回传修正后新的权值
					for(i = 0; i < 10; i++)
					{
						for(j = 0;j < 10; j++)
						{
							fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i];
						}
					}
					// 计算输入层至隐层的权值
					for(i = 0; i <16; i++)
					{
						for(j = 0; j < 10; j++)
						{
							fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i];
						}
					}

				}

			}while(bSingleEnd == FALSE);
			
		}
		// 用于判断用同一组权值对10个数字进行训练是否都满足条件
		int a = 0;
		for(i = 0; i < 9; i++)
		{
			if(fNumError[i][1] == fNumError[i+1][1]) 
				a++;
		}
		if(a==9)
			bAllEnd = TRUE;
		else
			bAllEnd = FALSE;
	}while(bAllEnd == FALSE);
//	AfxMessageBox("训练终于结束了!");


	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpHidWeight,"%10f",fHidWeight[i][j]);
		}
		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"w"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f",fOutWeight[i][j]);
			fprintf(fpOutWeight,"%10f",fOutWeight[i][j]);
		}
		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	return TRUE;
}


BOOL WINAPI BPReco()
{
	// 输入层至隐层的权值
	float fHidWeight[64][16];
	// 隐层至输出层的权值
	float fOutWeight[16][10];
	// 存储输入数据
	int iTranData[10][64];
	// 存储隐层的输入状态
	float fHidTemp[16];
	// 存储隐层的输出
	float fHidData[16];
	// 存储输出层的输入状态
	float fOutTemp[10];
	// 存储输出层的输出
	float fOutData[10];
	// 输出层至隐层的回传误差
//	double fOutError[10];
	// 隐层至输入层的回传误差
//	double fHidError[16];
	// 每一次对10个数字进行训练得到的误差
//	double fNumError[10][3];
	// 输出层教师的取值
//	double fTeacher[10][10];
	// 训练的步长
	float fStep = 0.2;
	// 对某个样本训练结束标志符
//	bool   bSingleEnd = FALSE;
	// 对全部样本训练结束标志符
//	bool   bAllEnd = FALSE;
	// 识别结果
	int iRecoResult;
	// 识别率
//	int iRecoRate;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值.dat";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值.dat";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比
//	int iNoise;
	// 存储加入噪声以后的识别数据
//	int iNoiseData[10][64];
	// 用于情况的选择
//	int iChoise;


	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 64; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%d",&iTranData[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
	}
	// 关闭文件
	fclose(fpTranData);

	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpHidWeight, 0L, SEEK_SET );

	for(i = 0; i < 64; i++)
	{
		for(j = 0; j < 16; j++)
		{
//			fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]);
			fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]);
		}
//		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpOutWeight, 0L, SEEK_SET );

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]);
			fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
//		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	///////////////////////////////////////////////////////
	// 识别

//	do
//	{
		////////////////////////////////////////////////////
		// 加入随机噪声
//        iNoise = 0 ;
//		iRecoRate = 0;

//		for(i=0;i<10;i++)
//		{
//			for(j=0;j<64;j++)
//			{
				// 每次识别加入的误差都是在原始数据基础上加上的
//				iNoiseData[i][j] = iTranData[i][j];
//				if((rand()/327.67)<iNoise)
//					iNoiseData[i][j] = 1 - iNoiseData[i][j];
//			}
//		}

		for(iTranNum = 0; iTranNum < 10; iTranNum++)
		{

			// 计算隐层各结点的值			
			for(i = 0; i < 16; i++)		// i代表隐层的各个结点
			{
				fHidTemp[i] = 0.0;
				for(j = 0; j < 64; j++) // j代表输入层的各个结点
				{
					fHidTemp[i] += fHidWeight[j][i] * (float)iTranData[iTranNum][j]; // ??????
				}

				// 根据传递函数公式求得隐层的输出
				fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
			}
			// 计算输出层各结点的值
			
			for(i = 0; i < 10; i++)		// i代表输出层的各个结点
			{
				fOutTemp[i] = 0.0;
				for(j = 0; j < 16; j++)	// j代表隐层的各个结点
				{
					fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
				}
				fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
			}
			// 根据输出确定识别结果
			float fTemp = 0.0;
			int   iMax = 0;
			for(i = 0; i < 10; i++)
			{
				if(fOutData[i] > fTemp)
				{
					fTemp = fOutData[i];	 // 判断准则:输出最大的结点的标号
					iMax  = i;
				}				
			}
			iRecoResult = iMax;
			TRACE("*** %d ***\n",iRecoResult);
//			TRACE("*** %10f ***\n",fOutWeight[0][0]);
//			cout<<"         识别结果为:"<<iRecoResult;

//			if(iRecoResult == iTranNum)
//				iRecoRate += 10;
		}

//		cout<<"   识别率为:"<<iRecoRate<<" %";
//		if(iRecoRate == 100)
//			cout<<"  太棒了!";
//		else if(iRecoRate >= 80)
//			cout<<"  嗯!不错! ";
//		else if(iRecoRate >= 60)
//			cout<<"  还行!还行!";
//		else
//			cout<<"  天哪!重新开始吧!";
//
//		cout<<"\n*** 改变噪声比例,继续识别,请按数字“1”  结束此程序的运行,请按下数字“0”:***";
//        iChoise = 3;
//		cin>>iChoise;
//	}while(iChoise==1);

//	if(iChoise==0)
//	{
//		cout<<endl;
//		cout<<"\n    谢谢您使用该软件。";//由于时间短促(我只写了两天)它还有许多不足,如:采用的";
//		cout<<"\n是最基本的算法、训练的速率不够高、网络的容错性一般,另外这是个DOS程序,还没有";
//		cout<<"\n实现Windows版本(呵呵,这是我课题要做的一部分)。所以,希望各位师弟师妹提出";
//		cout<<"请您提出宝贵意见,并加以完善! 再见!(请按任意键结束)";
//		cout<<"\n                                                     作者:王建   2001/6/27 ";
//		cout<<endl;
//	}
//	else 
//		cout<<endl<<"很抱歉,你作出了错误的选择,这将导致程序的结束!(请按任意键继续)"<<endl;


	return TRUE;
}

unsigned char WINAPI BPReco13Section(float* pRecoData)
{
	// 输入层至隐层的权值
	float fHidWeight[13][10];
	// 隐层至输出层的权值
	float fOutWeight[10][10];
	// 存储输入数据
	float fTranData[10][13];
	// 存储隐层的输入状态
	float fHidTemp[10];
	// 存储隐层的输出
	float fHidData[10];
	// 存储输出层的输入状态
	float fOutTemp[10];
	// 存储输出层的输出
	float fOutData[10];
	// 训练的步长
	float fStep = 0.2;
	unsigned char iRecoResult;
	// 存储识别数据
	float fRecoData[13];
	// 指向存有训练数据的文件的指针、文件名的字符串
//	FILE *fpTranData;
//	char *TranDataFileName = "训练数据_13段.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_13段.dat";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_13段.dat";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比
//	int iNoise;
	// 存储加入噪声以后的识别数据
//	int iNoiseData[10][64];
	// 用于情况的选择
//	int iChoise;


//	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
//	{
//		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
//		return 0;
//	}

	for(i = 0; i < 13; i++)
	{
		fRecoData[i] = *pRecoData;
		pRecoData++;
//		for(j = 0; j < 13; j++)
//		{
			// 将训练数据读入训练数据数组中
//			fscanf(fpTranData,"%f",&fTranData[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
//		}
	}
	// 关闭文件
//	fclose(fpTranData);

	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpHidWeight, 0L, SEEK_SET );

	for(i = 0; i < 13; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]);
			fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]);
		}
//		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpOutWeight, 0L, SEEK_SET );

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]);
			fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
//		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	///////////////////////////////////////////////////////
	// 识别


//		for(iTranNum = 0; iTranNum < 10; iTranNum++)
//		{

			// 计算隐层各结点的值			
			for(i = 0; i < 10; i++)		// i代表隐层的各个结点
			{
				fHidTemp[i] = 0.0;
				for(j = 0; j < 13; j++) // j代表输入层的各个结点
				{
//					fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ??????
					fHidTemp[i] += fHidWeight[j][i] * (float)fRecoData[j];
				}

				// 根据传递函数公式求得隐层的输出
				fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
			}
			// 计算输出层各结点的值
			
			for(i = 0; i < 10; i++)		// i代表输出层的各个结点
			{
				fOutTemp[i] = 0.0;
				for(j = 0; j < 10; j++)	// j代表隐层的各个结点
				{
					fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
				}
				fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
			}
			// 根据输出确定识别结果
			float fTemp = 0.0;
			int   iMax = 0;
			for(i = 0; i < 10; i++)
			{
				if(fOutData[i] > fTemp)
				{
					fTemp = fOutData[i];	 // 判断准则:输出最大的结点的标号
					iMax  = i;
				}				
			}
			iRecoResult = (unsigned char)iMax + 48;

//			TRACE("*** %d ***\n",iRecoResult);
//		}

	return iRecoResult;
}

unsigned char WINAPI BPReco16SectionNumber(float* pRecoData)
{
	// 输入层至隐层的权值
	float fHidWeight[16][10];
	// 隐层至输出层的权值
	float fOutWeight[10][10];
	// 存储输入数据
	float fTranData[10][16];
	// 存储隐层的输入状态
	float fHidTemp[10];
	// 存储隐层的输出
	float fHidData[10];
	// 存储输出层的输入状态
	float fOutTemp[10];
	// 存储输出层的输出
	float fOutData[10];
	// 训练的步长
	float fStep = 0.2;
	unsigned char iRecoResult;
	// 存储识别数据
	float fRecoData[16];
	// 指向存有训练数据的文件的指针、文件名的字符串
//	FILE *fpTranData;
//	char *TranDataFileName = "训练数据_13段.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_16段投影数字.txt";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_16段投影数字.txt";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比
//	int iNoise;
	// 存储加入噪声以后的识别数据
//	int iNoiseData[10][64];
	// 用于情况的选择
//	int iChoise;


//	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
//	{
//		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
//		return 0;
//	}

	for(i = 0; i < 16; i++)
	{
		fRecoData[i] = *pRecoData;
		pRecoData++;
//		for(j = 0; j < 13; j++)
//		{
			// 将训练数据读入训练数据数组中
//			fscanf(fpTranData,"%f",&fTranData[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
//		}
	}
	// 关闭文件
//	fclose(fpTranData);

	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpHidWeight, 0L, SEEK_SET );

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]);
			fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]);
		}
//		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpOutWeight, 0L, SEEK_SET );

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]);
			fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
//		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	///////////////////////////////////////////////////////
	// 识别


//		for(iTranNum = 0; iTranNum < 10; iTranNum++)
//		{

			// 计算隐层各结点的值			
			for(i = 0; i < 10; i++)		// i代表隐层的各个结点
			{
				fHidTemp[i] = 0.0;
				for(j = 0; j < 16; j++) // j代表输入层的各个结点
				{
//					fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ??????
					fHidTemp[i] += fHidWeight[j][i] * (float)fRecoData[j];
				}

				// 根据传递函数公式求得隐层的输出
				fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
			}
			// 计算输出层各结点的值
			
			for(i = 0; i < 10; i++)		// i代表输出层的各个结点
			{
				fOutTemp[i] = 0.0;
				for(j = 0; j < 10; j++)	// j代表隐层的各个结点
				{
					fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
				}
				fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
			}
			// 根据输出确定识别结果
			float fTemp = 0.0;
			int   iMax = 0;
			for(i = 0; i < 10; i++)
			{
				if(fOutData[i] > fTemp)
				{
					fTemp = fOutData[i];	 // 判断准则:输出最大的结点的标号
					iMax  = i;
				}				
			}
			iRecoResult = (unsigned char)iMax + 48;

//			TRACE("*** %d ***\n",iRecoResult);
//		}

	return iRecoResult;
}

unsigned char WINAPI BPReco16SectionLetter(float* pRecoData)
{
	// 输入层至隐层的权值
	float fHidWeight[16][10];
	// 隐层至输出层的权值
	float fOutWeight[10][26];
	// 存储输入数据
//	float fTranData[10][16];
	// 存储隐层的输入状态
	float fHidTemp[10];
	// 存储隐层的输出
	float fHidData[10];
	// 存储输出层的输入状态
	float fOutTemp[26];
	// 存储输出层的输出
	float fOutData[26];
	// 识别结果
	unsigned char iRecoResult;
	// 存储识别数据
	float fRecoData[16];
	// 指向存有训练数据的文件的指针、文件名的字符串
//	FILE *fpTranData;
//	char *TranDataFileName = "训练数据_13段.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_16段投影字母.txt";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_16段投影字母.txt";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;


	for(i = 0; i < 16; i++)
	{
		fRecoData[i] = *pRecoData;
		pRecoData++;
	}

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpHidWeight, 0L, SEEK_SET );

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]);
			fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]);
		}
//		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpOutWeight, 0L, SEEK_SET );

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 26; j++)
		{
//			fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]);
			fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
//		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	///////////////////////////////////////////////////////
	// 识别


//		for(iTranNum = 0; iTranNum < 10; iTranNum++)
//		{

			// 计算隐层各结点的值			
			for(i = 0; i < 10; i++)		// i代表隐层的各个结点
			{
				fHidTemp[i] = 0.0;
				for(j = 0; j < 16; j++) // j代表输入层的各个结点
				{
//					fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ??????
					fHidTemp[i] += fHidWeight[j][i] * (float)fRecoData[j];
				}

				// 根据传递函数公式求得隐层的输出
				fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
			}
			// 计算输出层各结点的值
			
			for(i = 0; i < 26; i++)		// i代表输出层的各个结点
			{
				fOutTemp[i] = 0.0;
				for(j = 0; j < 10; j++)	// j代表隐层的各个结点
				{
					fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
				}
				fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
			}
			// 根据输出确定识别结果
			float fTemp = 0.0;
			int   iMax = 0;
			for(i = 0; i < 26; i++)
			{
				if(fOutData[i] > fTemp)
				{
					fTemp = fOutData[i];	 // 判断准则:输出最大的结点的标号
					iMax  = i;
				}				
			}
			iRecoResult = (unsigned char)iMax + 65;

//			TRACE("*** %d ***\n",iRecoResult);
//		}

	return iRecoResult;
}



BOOL WINAPI BPRecoStruct()
{
	// 输入层至隐层的权值
	float fHidWeight[16][10];
	// 隐层至输出层的权值
	float fOutWeight[10][10];
	// 存储输入数据
	float fTranData[10][16];
	// 存储隐层的输入状态
	float fHidTemp[10];
	// 存储隐层的输出
	float fHidData[10];
	// 存储输出层的输入状态
	float fOutTemp[10];
	// 存储输出层的输出
	float fOutData[10];
	// 训练的步长
	float fStep = 0.2;
	int iRecoResult;
	// 指向存有训练数据的文件的指针、文件名的字符串
	FILE *fpTranData;
	char *TranDataFileName = "训练数据_微特征.dat ";
	// 指向存有已训练好的输入层至隐层的权值的文件的指针
	FILE *fpHidWeight;
	char *HidWeightName = "隐层权值_微特征.dat";
	// 指向存有已训练好的隐层至输出层的权值的文件的指针
	FILE *fpOutWeight;
	char *OutWeightName = "输出层权值_微特征.dat";
	// 循环变量
	int   i,j;
	// 正在训练或识别的数字
	int iTranNum;
	// 记录训练次数
	int icount=0;
	// 要加入的随机噪声的百分比
//	int iNoise;
	// 存储加入噪声以后的识别数据
//	int iNoiseData[10][64];
	// 用于情况的选择
//	int iChoise;


	if((fpTranData = fopen(TranDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 16; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpTranData,"%f",&fTranData[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
	}
	// 关闭文件
	fclose(fpTranData);

	/////////////////////////////////////////////////////////
	// 存储训练好的权值

	// 存储输入层至隐层的权值
	if((fpHidWeight = fopen(HidWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpHidWeight, 0L, SEEK_SET );

	for(i = 0; i < 16; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]);
			fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]);
		}
//		fprintf(fpHidWeight,"\n","");
	}
	fclose(fpHidWeight);

	// 存储隐层至输出层的权值
	if((fpOutWeight = fopen(OutWeightName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

    fseek( fpOutWeight, 0L, SEEK_SET );

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 10; j++)
		{
//			fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]);
			fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]);
//			iNoiseData[i][j] = iTranData[i][j];
		}
//		fprintf(fpOutWeight,"\n","");
	}
	fclose(fpOutWeight);

	///////////////////////////////////////////////////////
	// 识别


		for(iTranNum = 0; iTranNum < 10; iTranNum++)
		{

			// 计算隐层各结点的值			
			for(i = 0; i < 10; i++)		// i代表隐层的各个结点
			{
				fHidTemp[i] = 0.0;
				for(j = 0; j < 16; j++) // j代表输入层的各个结点
				{
					fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ??????
				}

				// 根据传递函数公式求得隐层的输出
				fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) );
			}
			// 计算输出层各结点的值
			
			for(i = 0; i < 10; i++)		// i代表输出层的各个结点
			{
				fOutTemp[i] = 0.0;
				for(j = 0; j < 10; j++)	// j代表隐层的各个结点
				{
					fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; 
				}
				fOutData[i] =  1.0 / ( 1.0 + exp(-fOutTemp[i]) );
			}
			// 根据输出确定识别结果
			float fTemp = 0.0;
			int   iMax = 0;
			for(i = 0; i < 10; i++)
			{
				if(fOutData[i] > fTemp)
				{
					fTemp = fOutData[i];	 // 判断准则:输出最大的结点的标号
					iMax  = i;
				}				
			}
			iRecoResult = iMax;
			TRACE("*** %d ***\n",iRecoResult);
		}



	return TRUE;
}
/*************************************************************************
 *
 * 函数名称:
 *   ContourDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行轮廓提取运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI ContourDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;
	unsigned char n,e,s,w,ne,se,nw,sw;

	//像素值
	unsigned char pixel;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);
	for(j = 1; j <lHeight-1; j++)
	{
		for(i = 1;i <lWidth-1; i++)
		{
			
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lWidth * j + i;
			
			// 指向目标图像倒数第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lWidth * j + i;
			
			//取得当前指针处的像素值,注意要转换为unsigned char型
			pixel = (unsigned char)*lpSrc;

			//目标图像中含有0和255外的其它灰度值
//			if(pixel != 255 && pixel != 0)
//				return FALSE;
			if(pixel == 0)
			{
				*lpDst = (unsigned char)0;
				nw = (unsigned char)*(lpSrc + lWidth -1);
				n  = (unsigned char)*(lpSrc + lWidth );
				ne = (unsigned char)*(lpSrc + lWidth +1);
				w = (unsigned char)*(lpSrc -1);
				e = (unsigned char)*(lpSrc +1);
				sw = (unsigned char)*(lpSrc - lWidth -1);
				s  = (unsigned char)*(lpSrc - lWidth );
				se = (unsigned char)*(lpSrc - lWidth +1);
				//如果相邻的八个点都是黑点
				if(nw+n+ne+w+e+sw+s+se==0)
				{
					*lpDst = (unsigned char)255;
				}
			}
		}
	}

	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   TraceDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行轮廓跟踪运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI TraceDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	// 图像每行的字节数
	LONG lLineBytes;
	
	//循环变量
	long i;
	long j;

	//像素值
	unsigned char pixel;

	//是否找到起始点及回到起始点
	bool bFindStartPoint;

	//是否扫描到一个边界点
	bool bFindPoint;

	//起始边界点与当前边界点
	Point StartPoint,CurrentPoint;

	//八个方向和起始扫描方向
	int Direction[8][2]={{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0}};
	int BeginDirect;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lLineBytes * lHeight);

	//先找到最左上方的边界点
	bFindStartPoint = false;
	for (j = 0;j < lHeight && !bFindStartPoint;j++)
	{
		for(i = 0;i < lWidth && !bFindStartPoint;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
			
			//取得当前指针处的像素值,注意要转换为unsigned char型
			pixel = (unsigned char)*lpSrc;
			
			if(pixel == 0)
			{
				bFindStartPoint = true;

				StartPoint.Height = j;
				StartPoint.Width = i;

				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;	
				*lpDst = (unsigned char)0;
			}		
		}
	}

	//由于起始点是在左下方,故起始扫描沿左上方向
	BeginDirect = 0;
	//跟踪边界
	bFindStartPoint = false;
	//从初始点开始扫描
	CurrentPoint.Height = StartPoint.Height;
	CurrentPoint.Width = StartPoint.Width;
	while(!bFindStartPoint)
	{
		bFindPoint = false;
		while(!bFindPoint)
		{
			//沿扫描方向查看一个像素
			lpSrc = (char *)lpDIBBits + lLineBytes * ( CurrentPoint.Height + Direction[BeginDirect][1])
				+ (CurrentPoint.Width + Direction[BeginDirect][0]);
			pixel = (unsigned char)*lpSrc;
			if(pixel == 0)
			{
				bFindPoint = true;
				CurrentPoint.Height = CurrentPoint.Height + Direction[BeginDirect][1];
				CurrentPoint.Width = CurrentPoint.Width + Direction[BeginDirect][0];
				if(CurrentPoint.Height == StartPoint.Height && CurrentPoint.Width == StartPoint.Width)
				{
					bFindStartPoint = true;
				}
				lpDst = (char *)lpNewDIBBits + lLineBytes * CurrentPoint.Height + CurrentPoint.Width;
				*lpDst = (unsigned char)0;
				//扫描的方向逆时针旋转两格
				BeginDirect--;
				if(BeginDirect == -1)
					BeginDirect = 7;
				BeginDirect--;
				if(BeginDirect == -1)
					BeginDirect = 7;
			}
			else
			{
				//扫描方向顺时针旋转一格
				BeginDirect++;
				if(BeginDirect == 8)
					BeginDirect = 0;

			}

		}
	}

	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   FFT()
 *
 * 参数:
 *   complex<double> * TD	- 指向时域数组的指针
 *   complex<double> * FD	- 指向频域数组的指针
 *   r						-2的幂数,即迭代次数
 *
 * 返回值:
 *   无。
 *
 * 说明:
 *   该函数用来实现快速付立叶变换。
 *
 ************************************************************************/
VOID WINAPI FFT(complex<double> * TD, complex<double> * FD, int r)
{
	// 付立叶变换点数
	LONG	count;
	
	// 循环变量
	int		i,j,k;
	
	// 中间变量
	int		bfsize,p;
	
	// 角度
	double	angle;
	
	complex<double> *W,*X1,*X2,*X;
	
	// 计算付立叶变换点数
	count = 1 << r;
	
	// 分配运算所需存储器
	W  = new complex<double>[count / 2];
	X1 = new complex<double>[count];
	X2 = new complex<double>[count];
	
	// 计算加权系数
	for(i = 0; i < count / 2; i++)
	{
		angle = -i * PI * 2 / count;
		W[i] = complex<double> (cos(angle), sin(angle));
	}
	
	// 将时域点写入X1
	memcpy(X1, TD, sizeof(complex<double>) * count);
	
	// 采用蝶形算法进行快速付立叶变换
	for(k = 0; k < r; k++)
	{
		for(j = 0; j < 1 << k; j++)
		{
			bfsize = 1 << (r-k);
			for(i = 0; i < bfsize / 2; i++)
			{
				p = j * bfsize;
				X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
				X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2]) * W[i * (1<<k)];
			}
		}
		X  = X1;
		X1 = X2;
		X2 = X;
	}
	
	// 重新排序
	for(j = 0; j < count; j++)
	{
		p = 0;
		for(i = 0; i < r; i++)
		{
			if (j&(1<<i))
			{
				p+=1<<(r-i-1);
			}
		}
		FD[j]=X1[p];
	}
	
	// 释放内存
	delete W;
	delete X1;
	delete X2;
}

/*************************************************************************
 *
 * 函数名称:
 *   IFFT()
 *
 * 参数:
 *   complex<double> * FD	- 指向频域值的指针
 *   complex<double> * TD	- 指向时域值的指针
 *   r						-2的幂数
 *
 * 返回值:
 *   无。
 *
 * 说明:
 *   该函数用来实现快速付立叶反变换。
 *
 ************************************************************************/
VOID WINAPI IFFT(complex<double> * FD, complex<double> * TD, int r)
{
	// 付立叶变换点数
	LONG	count;
	
	// 循环变量
	int		i;
	
	complex<double> *X;
	
	// 计算付立叶变换点数
	count = 1 << r;
	
	// 分配运算所需存储器
	X = new complex<double>[count];
	
	// 将频域点写入X
	memcpy(X, FD, sizeof(complex<double>) * count);
	
	// 求共轭
	for(i = 0; i < count; i++)
	{
		X[i] = complex<double> (X[i].real(), -X[i].imag());
	}
	
	// 调用快速付立叶变换
	FFT(X, TD, r);
	
	// 求时域点的共轭
	for(i = 0; i < count; i++)
	{
		TD[i] = complex<double> (TD[i].real() / count, -TD[i].imag() / count);
	}
	
	// 释放内存
	delete X;
}

/*************************************************************************
 *
 * 函数名称:
 *   Fourier()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行付立叶变换。
 *
 ************************************************************************/
BOOL WINAPI Fourier(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 中间变量
	double	dTemp;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 进行付立叶变换的宽度和高度(2的整数次方)
	LONG	w;
	LONG	h;
	
	int		wp;
	int		hp;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 赋初值
	w = 1;
	h = 1;
	wp = 0;
	hp = 0;
	
	// 计算进行付立叶变换的宽度和高度(2的整数次方)
	while(w * 2 <= lWidth)
	{
		w *= 2;
		wp++;
	}
	
	while(h * 2 <= lHeight)
	{
		h *= 2;
		hp++;
	}
	
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];
	
	// 行
	for(i = 0; i < h; i++)
	{
		// 列
		for(j = 0; j < w; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 给时域赋值
			TD[j + w * i] = complex<double>(*(lpSrc), 0);
		}
	}
	
	for(i = 0; i < h; i++)
	{
		// 对y方向进行快速付立叶变换
		FFT(&TD[w * i], &FD[w * i], wp);
	}
	
	// 保存变换结果
	for(i = 0; i < h; i++)
	{
		for(j = 0; j < w; j++)
		{
			TD[i + h * j] = FD[j + w * i];
		}
	}
	
	for(i = 0; i < w; i++)
	{
		// 对x方向进行快速付立叶变换
		FFT(&TD[i * h], &FD[i * h], hp);
	}
	
	// 行
	for(i = 0; i < h; i++)
	{
		// 列
		for(j = 0; j < w; j++)
		{
			// 计算频谱
			dTemp = sqrt(FD[j * h + i].real() * FD[j * h + i].real() + 
				         FD[j * h + i].imag() * FD[j * h + i].imag()) / 100;
			
			// 判断是否超过255
			if (dTemp > 255)
			{
				// 对于超过的,直接设置为255
				dTemp = 255;
			}
			
			// 指向DIB第(i<h/2 ? i+h/2 : i-h/2)行,第(j<w/2 ? j+w/2 : j-w/2)个象素的指针
			// 此处不直接取i和j,是为了将变换后的原点移到中心
			//lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * 
				(lHeight - 1 - (i<h/2 ? i+h/2 : i-h/2)) + (j<w/2 ? j+w/2 : j-w/2);
			
			// 更新源图像
			* (lpSrc) = (BYTE)(dTemp);
		}
	}
	
	// 删除临时变量
	delete TD;
	delete FD;
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   DCT()
 *
 * 参数:
 *   double * f				- 指向时域值的指针
 *   double * F				- 指向频域值的指针
 *   r						-2的幂数
 *
 * 返回值:
 *   无。
 *
 * 说明:
 *   该函数用来实现快速离散余弦变换。该函数利用2N点的快速付立叶变换
 * 来实现离散余弦变换。
 *
 ************************************************************************/
VOID WINAPI DCT(double *f, double *F, int r)
{
	// 离散余弦变换点数
	LONG	count;
	
	// 循环变量
	int		i;
	
	// 中间变量
	double	dTemp;
	
	complex<double> *X;
	
	// 计算离散余弦变换点数
	count = 1<<r;
	
	// 分配内存
	X = new complex<double>[count*2];
	
	// 赋初值为0
	memset(X, 0, sizeof(complex<double>) * count * 2);
	
	// 将时域点写入数组X
	for(i=0;i<count;i++)
	{
		X[i] = complex<double> (f[i], 0);
	}
	
	// 调用快速付立叶变换
	FFT(X,X,r+1);
	
	// 调整系数
	dTemp = 1/sqrt(count);
	
	// 求F[0]
	F[0] = X[0].real() * dTemp;
	
	dTemp *= sqrt(2);
	
	// 求F[u]	
	for(i = 1; i < count; i++)
	{
		F[i]=(X[i].real() * cos(i*PI/(count*2)) + X[i].imag() * sin(i*PI/(count*2))) * dTemp;
	}
	
	// 释放内存
	delete X;
}

/*************************************************************************
 *
 * 函数名称:
 *   IDCT()
 *
 * 参数:
 *   double * F				- 指向频域值的指针
 *   double * f				- 指向时域值的指针
 *   r						-2的幂数
 *
 * 返回值:
 *   无。
 *
 * 说明:
 *   该函数用来实现快速离散余弦反变换。该函数也利用2N点的快速付立叶变换
 * 来实现离散余弦反变换。
 *
 ************************************************************************/
VOID WINAPI IDCT(double *F, double *f, int r)
{
	// 离散余弦反变换点数
	LONG	count;
	
	// 循环变量
	int		i;
	
	// 中间变量
	double	dTemp, d0;
	
	complex<double> *X;
	
	// 计算离散余弦变换点数
	count = 1<<r;
	
	// 分配内存
	X = new complex<double>[count*2];
	
	// 赋初值为0
	memset(X, 0, sizeof(complex<double>) * count * 2);
	
	// 将频域变换后点写入数组X
	for(i=0;i<count;i++)
	{
		X[i] = complex<double> (F[i] * cos(i*PI/(count*2)), F[i] * sin(i*PI/(count*2)));
	}
	
	// 调用快速付立叶反变换
	IFFT(X,X,r+1);
	
	// 调整系数
	dTemp = sqrt(2.0/count);
	d0 = (sqrt(1.0/count) - dTemp) * F[0];
	
	// 计算f(x)
	for(i = 0; i < count; i++)
	{
		f[i] = d0 + X[i].real()* dTemp * 2 * count;
	}
	
	// 释放内存
	delete X;
}

/*************************************************************************
 *
 * 函数名称:
 *   DIBDct()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行离散余弦变换。
 *
 ************************************************************************/
BOOL WINAPI DIBDct(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 进行付立叶变换的宽度和高度(2的整数次方)
	LONG	w;
	LONG	h;
	
	// 中间变量
	double	dTemp;
	
	int		wp;
	int		hp;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 赋初值
	w = 1;
	h = 1;
	wp = 0;
	hp = 0;
	
	// 计算进行离散余弦变换的宽度和高度(2的整数次方)
	while(w * 2 <= lWidth)
	{
		w *= 2;
		wp++;
	}
	
	while(h * 2 <= lHeight)
	{
		h *= 2;
		hp++;
	}
	
	// 分配内存
	double *f = new double[w * h];
	double *F = new double[w * h];
	
	// 行
	for(i = 0; i < h; i++)
	{
		// 列
		for(j = 0; j < w; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 给时域赋值
			f[j + i * w] = *(lpSrc);
		}
	}
	
	for(i = 0; i < h; i++)
	{
		// 对y方向进行离散余弦变换
		DCT(&f[w * i], &F[w * i], wp);
	}
	
	// 保存计算结果
	for(i = 0; i < h; i++)
	{
		for(j = 0; j < w; j++)
		{
			f[j * h + i] = F[j + w * i];
		}
	}
	
	for(j = 0; j < w; j++)
	{
		// 对x方向进行离散余弦变换
		DCT(&f[j * h], &F[j * h], hp);
	}
	
	// 行
	for(i = 0; i < h; i++)
	{
		// 列
		for(j = 0; j < w; j++)
		{
			// 计算频谱
			dTemp = fabs(F[j*h+i]);
			
			// 判断是否超过255
			if (dTemp > 255)
			{
				// 对于超过的,直接设置为255
				dTemp = 255;
			}
			
			// 指向DIB第y行,第x个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 更新源图像
			* (lpSrc) = (BYTE)(dTemp);
		}
	}
	
	// 释放内存
	delete f;
	delete F;

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   WALSH()
 *
 * 参数:
 *   double * f				- 指向时域值的指针
 *   double * F				- 指向频域值的指针
 *   r						-2的幂数
 *
 * 返回值:
 *   无。
 *
 * 说明:
 *   该函数用来实现快速沃尔什-哈达玛变换。
 *
 ************************************************************************/

VOID WINAPI WALSH(double *f, double *F, int r)
{
	// 沃尔什-哈达玛变换点数
	LONG	count;
	
	// 循环变量
	int		i,j,k;
	
	// 中间变量
	int		bfsize,p;
	
	double *X1,*X2,*X;
	
	// 计算快速沃尔什变换点数
	count = 1 << r;
	
	// 分配运算所需的数组
	X1 = new double[count];
	X2 = new double[count];
	
	// 将时域点写入数组X1
	memcpy(X1, f, sizeof(double) * count);
	
	// 蝶形运算
	for(k = 0; k < r; k++)
	{
		for(j = 0; j < 1<<k; j++)
		{
			bfsize = 1 << (r-k);
			for(i = 0; i < bfsize / 2; i++)
			{
				p = j * bfsize;
				X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
				X2[i + p + bfsize / 2] = X1[i + p] - X1[i + p + bfsize / 2];
			}
		}
		
		// 互换X1和X2  
		X = X1;
		X1 = X2;
		X2 = X;
	}
	
	// 调整系数
	for(j = 0; j < count; j++)
	{
		p = 0;
		for(i = 0; i < r; i++)
		{
			if (j & (1<<i))
			{
				p += 1 << (r-i-1);
			}
		}

		F[j] = X1[p] / count;
	}
	
	// 释放内存
	delete X1;
	delete X2;
}

/*************************************************************************
 *
 * 函数名称:
 *   IWALSH()
 *
 * 参数:
 *   double * F				- 指向频域值的指针
 *   double * f				- 指向时域值的指针
 *   r						-2的幂数
 *
 * 返回值:
 *   无。
 *
 * 说明:
 *   该函数用来实现快速沃尔什-哈达玛反变换。
 *
 ************************************************************************/

VOID WINAPI IWALSH(double *F, double *f, int r)
{
	// 变换点数
	LONG	count;
	
	// 循环变量
	int		i;
	
	// 计算变换点数
	count = 1 << r;
	
	// 调用快速沃尔什-哈达玛变换进行反变换
	WALSH(F, f, r);
	
	// 调整系数
	for(i = 0; i < count; i++)
	{
		f[i] *= count;
	}
}

/*************************************************************************
 *
 * 函数名称:
 *   DIBWalsh()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行沃尔什-哈达玛变换。函数首先对图像每列进行一维
 * 沃尔什-哈达玛变换,然后对变换结果的每行进行一维沃尔什-哈达玛变换。
 *
 ************************************************************************/

BOOL WINAPI DIBWalsh(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 进行付立叶变换的宽度和高度(2的整数次方)
	LONG	w;
	LONG	h;
	
	// 中间变量
	double	dTemp;
	
	int		wp;
	int		hp;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 赋初值
	w = 1;
	h = 1;
	wp = 0;
	hp = 0;
	
	// 计算进行离散余弦变换的宽度和高度(2的整数次方)
	while(w * 2 <= lWidth)
	{
		w *= 2;
		wp++;
	}
	
	while(h * 2 <= lHeight)
	{
		h *= 2;
		hp++;
	}
	
	// 分配内存
	double *f = new double[w * h];
	double *F = new double[w * h];
	
	// 行
	for(i = 0; i < h; i++)
	{
		// 列
		for(j = 0; j < w; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 给时域赋值
			f[j + i * w] = *(lpSrc);
		}
	}
	
	for(i = 0; i < h; i++)
	{
		// 对y方向进行沃尔什-哈达玛变换
		WALSH(f + w * i, F + w * i, wp);
	}
	
	// 保存计算结果
	for(i = 0; i < h; i++)
	{
		for(j = 0; j < w; j++)
		{
			f[j * h + i] = F[j + w * i];
		}
	}
	
	for(j = 0; j < w; j++)
	{
		// 对x方向进行沃尔什-哈达玛变换
		WALSH(f + j * h, F + j * h, hp);
	}
	
	// 行
	for(i = 0; i < h; i++)
	{
		// 列
		for(j = 0; j < w; j++)
		{
			// 计算频谱
			dTemp = fabs(F[j * h + i] * 1000);
			
			// 判断是否超过255
			if (dTemp > 255)
			{
				// 对于超过的,直接设置为255
				dTemp = 255;
			}
			
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 更新源图像
			* (lpSrc) = (BYTE)(dTemp);
		}
	}
	
	//释放内存
	delete f;
	delete F;

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   DIBWalsh1()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行沃尔什-哈达玛变换。于上面不同的是,此处是将二维
 * 矩阵转换成一个列向量,然后对该列向量进行一次一维沃尔什-哈达玛变换。
 *
 ************************************************************************/

BOOL WINAPI DIBWalsh1(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 进行付立叶变换的宽度和高度(2的整数次方)
	LONG	w;
	LONG	h;
	
	// 中间变量
	double	dTemp;
	
	int		wp;
	int		hp;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 赋初值
	w = 1;
	h = 1;
	wp = 0;
	hp = 0;
	
	// 计算进行离散余弦变换的宽度和高度(2的整数次方)
	while(w * 2 <= lWidth)
	{
		w *= 2;
		wp++;
	}
	
	while(h * 2 <= lHeight)
	{
		h *= 2;
		hp++;
	}
	
	// 分配内存
	double *f = new double[w * h];
	double *F = new double[w * h];
	
	// 列
	for(i = 0; i < w; i++)
	{
		// 行
		for(j = 0; j < h; j++)
		{
			// 指向DIB第j行,第i个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - j) + i;
			
			// 给时域赋值
			f[j + i * w] = *(lpSrc);
		}
	}
	
	// 调用快速沃尔什-哈达玛变换
	WALSH(f, F, wp + hp);
	
	// 列
	for(i = 0; i < w; i++)
	{
		// 行
		for(j = 0; j < h; j++)
		{
			// 计算频谱
			dTemp = fabs(F[i * w + j] * 1000);
			
			// 判断是否超过255
			if (dTemp > 255)
			{
				// 对于超过的,直接设置为255
				dTemp = 255;
			}
			
			// 指向DIB第j行,第i个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - j) + i;
			
			// 更新源图像
			* (lpSrc) = (BYTE)(dTemp);
		}
	}
	
	//释放内存
	delete f;
	delete F;

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   ThresholdDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行阈值分割运算。
 * 
 ************************************************************************/

BOOL WINAPI ThresholdDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	//像素值
	unsigned char pixel;

	//直方图数组
	long lHistogram[256];

	//阈值,最大灰度值与最小灰度值,两个区域的平均灰度值
	unsigned char iThreshold,iNewThreshold,iMaxGrayValue,iMinGrayValue,iMean1GrayValue,iMean2GrayValue;

	//用于计算区域灰度平均值的中间变量
	long lP1,lP2,lS1,lS2;

	//迭代次数
	int iIterationTimes;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for (i = 0; i < 256;i++)
	{
		lHistogram[i]=0;
	}

	//获得直方图
	iMaxGrayValue = 0;
	iMinGrayValue = 255;
	for (i = 0;i < lWidth ;i++)
	{
		for(j = 0;j < lHeight ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;
			
			lHistogram[pixel]++;
			//修改最大,最小灰度值
			if(iMinGrayValue > pixel)
			{
				iMinGrayValue = pixel;
			}
			if(iMaxGrayValue < pixel)
			{
				iMaxGrayValue = pixel;
			}
		}
	}

	//迭代求最佳阈值
	iNewThreshold = (iMinGrayValue + iMaxGrayValue)/2;
	iThreshold = 0;
	
	for(iIterationTimes = 0; iThreshold != iNewThreshold && iIterationTimes < 100;iIterationTimes ++)
	{
		iThreshold = iNewThreshold;
		lP1 =0;
		lP2 =0;
		lS1 = 0;
		lS2 = 0;
		//求两个区域的灰度平均值
		for (i = iMinGrayValue;i < iThreshold;i++)
		{
			lP1 += lHistogram[i]*i;
			lS1 += lHistogram[i];
		}
		iMean1GrayValue = (unsigned char)(lP1 / lS1);
		for (i = iThreshold+1;i < iMaxGrayValue;i++)
		{
			lP2 += lHistogram[i]*i;
			lS2 += lHistogram[i];
		}
		iMean2GrayValue = (unsigned char)(lP2 / lS2);
		iNewThreshold =  (iMean1GrayValue + iMean2GrayValue)/2;
	}

	//根据阈值将图像二值化
	for (i = 0;i < lWidth ;i++)
	{
		for(j = 0;j < lHeight ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			// 指向目标图像倒数第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;

			pixel = (unsigned char)*lpSrc;
			
			if(pixel <= iThreshold)
			{
				*lpDst = (unsigned char)0;
			}
			else
			{
				*lpDst = (unsigned char)255;
			}
		}
	}

	// 复制图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   AddMinusDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LPSTR lpDIBBitsBK  - 指向背景DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *	 bool  bAddMinus	- 为true时执行加运算,否则执行减运算。
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行加减运算。
 * 
 * 要求目标图像为255个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI AddMinusDIB(LPSTR lpDIBBits, LPSTR lpDIBBitsBK, LONG lWidth, LONG lHeight ,bool bAddMinus)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc,lpSrcBK;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	//像素值
	unsigned char pixel,pixelBK;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for (j = 0;j < lHeight ;j++)
	{
		for(i = 0;i < lWidth ;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrcBK = (char *)lpDIBBitsBK + lLineBytes * j + i;
	
			// 指向目标图像倒数第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;

			pixel = (unsigned char)*lpSrc;
			pixelBK = (unsigned char)*lpSrcBK;
			if(bAddMinus)
				*lpDst = pixel + pixelBK > 255 ? 255 : pixel + pixelBK;
			else
				*lpDst = pixel - pixelBK < 0 ? 0 : pixel - pixelBK;


		}
	}

			
	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   HprojectDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行水平投影运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI HprojectDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	//图像中每行内的黑点个数
	long lBlackNumber;

	//像素值
	unsigned char pixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for (j = 0;j < lHeight ;j++)
	{
		lBlackNumber = 0;
		for(i = 0;i < lWidth ;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;

			if (pixel != 255 && pixel != 0)
			{
				return false;
			}
			if(pixel == 0)
			{
				lBlackNumber++;
			}
		}
		for(i = 0;i < lBlackNumber ;i++)
		{	
			// 指向目标图像倒数第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lLineBytes * j + (lWidth - i);

			*lpDst = (unsigned char)0;
		}		
	}

			
	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

BOOL WINAPI HDifferProjDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber);

	lTotalNumber = new long[1000];//平滑模板
	lSmooth1 = new long[1000];
	lSmooth2 = new long[1000];
	lBlackNumber = new long[1000];
	long lMax;

	float fAlpha;

	fAlpha = 0.2;

	//像素值
	unsigned char pixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为	
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(i = 0; i < 1000; i++)
	{
		lTotalNumber[i] = 0;
		lBlackNumber[i] = 0;
		lSmooth1[i] = 0; 
		lSmooth2[i] = 0; 
	}

	for (j = 0;j < lHeight ;j++)
	{
		for(i = 0;i < lWidth ;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;
	
			lTotalNumber[j] += pixel;
		}
	}
	// 求最大值
	lMax = 0;
	for(i = 0; i < 1000;i++)
	{
		if(lTotalNumber[i] >= lMax)
		{
			lMax = lTotalNumber[i];
		}
	}

	// 平滑
	lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax));
	lSmooth2[0] = lSmooth1[0];
    lBlackNumber[0] = lSmooth2[0];

	// 一次平滑
	for (j = 1;j < lHeight ;j++)
	{
		lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax));
		lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]);
//		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
	}
	// 二次平滑
	for (j = 1;j < lHeight ;j++)
	{
		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
	}

	// 赋值
	for (j = 0;j < lHeight ;j++)
	{
		for(i = 0;i < lBlackNumber[j] ;i++)
		{	
			// 指向目标图像倒数第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lLineBytes * j + (lWidth - i);

			*lpDst = (unsigned char)0;
		}		
	}

			
	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	delete []lTotalNumber;
	delete []lBlackNumber;
	delete []lSmooth1;
	delete []lSmooth2;
	// 返回
	return TRUE;
}

BOOL WINAPI HDifferProjDIB2(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	int iExtrem;

	long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber);
	long (*lDiffer);
	int  (*iMaxOrMin);  

	lTotalNumber = new long[1000];//平滑模板
	lSmooth1 = new long[1000];
	lSmooth2 = new long[1000];
	lBlackNumber = new long[1000];
	lDiffer = new long[1000];
	iMaxOrMin = new int[1000];
	long lMax;

	float fAlpha;

	fAlpha = 0.2;

	//像素值
	unsigned char pixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(i = 0; i < 1000; i++)
	{
		lTotalNumber[i] = 0;
		lBlackNumber[i] = 0;
		lSmooth1[i] = 0; 
		lSmooth2[i] = 0;
		lDiffer[i] = 0;
		iMaxOrMin[i] = 0;
	}

	for (j = 0;j < lHeight ;j++)
	{
		for(i = 0;i < lWidth ;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;
	
			lTotalNumber[j] += pixel;
		}
	}
	// 求最大值
	lMax = 0;
	for(i=0;i<1000;i++)
	{
		if(lTotalNumber[i] >= lMax)
		{
			lMax = lTotalNumber[i];
		}
	}

	// 平滑
	lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax));
	lSmooth2[0] = lSmooth1[0];
    lBlackNumber[0] = lSmooth2[0];

	// 一次平滑
	for (j = 1;j < lHeight ;j++)
	{
//		lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax));
		lSmooth1[j] = lTotalNumber[j];
		lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]);
//		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
	}
	// 二次平滑
	for (j = 1;j < lHeight ;j++)
	{
		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
		lDiffer[j - 1] = lBlackNumber[j] - lBlackNumber[j - 1];
	}

	// 判断极值
	iExtrem = 1;
	for (j = 1;j < lHeight ;j++)
	{
		// 极大值
//		if((lBlackNumber[j-1]>lBlackNumber[j])&&(lBlackNumber[j+1]>=lBlackNumber[j]))
		if((lDiffer[j - 1] > 0)&&(lDiffer[j] <= 0))
		{
			iMaxOrMin[iExtrem] = j;
			iExtrem++;
		}
		// 极小值
//		else if((lBlackNumber[j-1]<=lBlackNumber[j])&&(lBlackNumber[j+1]<lBlackNumber[j]))
		else if((lDiffer[j - 1] < 0)&&(lDiffer[j] >= 0))
		{
			iMaxOrMin[iExtrem] = -1 * j;
			iExtrem++;
		}
	}

	// 提取有效波谷
	i=iExtrem-1;
	j=iExtrem-2;
	int a1,a2,a3,a4,a5,a6,b1,b2,b3;
	do
	{
		int q1 =0;
		a1 = iMaxOrMin[i];
		a2 = iMaxOrMin[j];
		a3 = iMaxOrMin[j-1];
		if(i<iExtrem-2)
		{
			a4=iMaxOrMin[i+1];
			a5=iMaxOrMin[i+2];
		}
		b1 = lBlackNumber[abs(iMaxOrMin[i])];
		b2 = lBlackNumber[abs(iMaxOrMin[j])];
		b3 = lBlackNumber[abs(iMaxOrMin[j-1])];
		int q3=0;


		// 前为极大值,后为极大值
		if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] )
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;
				j = j - 1;
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i - 1;
			}
		}
		// 前为极小值,后为极小值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j])])
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;//j=j+1
				j = j - 1;//
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i - 1;
			}
		}
		// 前为极大值,后为极小值		 
		else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) 
			&& (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 50))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  >= lBlackNumber[abs(iMaxOrMin[j - 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j - 1] = 0;
				j = j - 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j - 1;
				j = i - 1;
			}
		}
		// 前为极小值,后为极大值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0)
			     && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 50))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j - 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j - 1] = 0;
				j = j - 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j - 1;
				j = i - 1;
			}
		}

		else
		{
			i = j;
			j = j - 1;
		}

		int q2=0;
	}while( j > 1);

/*	i=1;
	j=2;
	int a1,a2,a3,a4,a5,a6,b1,b2,b3;
	do
	{
		int q1 =0;
		a1 = iMaxOrMin[i];
		a2 = iMaxOrMin[j];
		a3 = iMaxOrMin[j+1];
		if(i>1)
		{
			a4=iMaxOrMin[i-1];
			a5=iMaxOrMin[i-2];
		}
		b1 = lBlackNumber[abs(iMaxOrMin[i])];
		b2 = lBlackNumber[abs(iMaxOrMin[j])];
		b3 = lBlackNumber[abs(iMaxOrMin[j+1])];
		int q3=0;


		// 前为极大值,后为极大值
		if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] )
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;
				j = j + 1;
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i + 1;
			}
		}
		// 前为极小值,后为极小值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j])])
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;//j=j+1
				j = j + 1;//
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i + 1;
			}
		}
		// 前为极大值,后为极小值		 
		else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) 
			&& (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 30))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  >= lBlackNumber[abs(iMaxOrMin[j + 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j + 1] = 0;
				j = j + 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j + 1;
				j = i + 1;
			}
		}
		// 前为极小值,后为极大值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0)
			     && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 30))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j + 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j + 1] = 0;
				j = j + 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j + 1;
				j = i + 1;
			}
		}

		else
		{
			i = j;
			j = j + 1;
		}

		int q2=0;
	}while( j < iExtrem);
*/
/*
	do
	{
		int q=0;
		// 前为极大值,后为极大值
		if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] )
			{
				iMaxOrMin[j] = 0;
				i = j + 1;
				j = i + 1;
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i + 1;
			}
		}
		// 前为极小值,后为极小值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j])])
			{
				iMaxOrMin[j] = 0;
				i = j + 1;//j=j+1
				j = i + 1;//
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i + 1;
			}
		}
		// 前为极大值,后为极小值		 
		else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) 
			&& (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 20))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  >= lBlackNumber[abs(iMaxOrMin[j + 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j + 1] = 0;
				j = j + 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j + 1;
				j = i + 1;
			}
		}
		// 前为极小值,后为极大值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0)
			     && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 20))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j + 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j + 1] = 0;
				j = j + 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j + 1;
				j = i + 1;
			}
		}

		else
		{
			i = j;
			j = j + 1;
		}

	}while( j < iExtrem);
*/
//		lSmooth1[j] = (long)( lWidth * lBlackNumber[j] / ( 2 * lMax));
	for (j = 1;j < iExtrem ;j++)
	{
		a1=iMaxOrMin[j];
		a2=lBlackNumber[abs(iMaxOrMin[j])];
		a3=0;
	}
	
	// 赋值
	for (j = 1;j < iExtrem ;j++)
	{
		int q5=0;
		a1=iMaxOrMin[j];
		a2=abs(iMaxOrMin[j]);
		a3=lBlackNumber[abs(iMaxOrMin[j])];
		a4=0;
		if(iMaxOrMin[j] < 0)//||(iMaxOrMin[j] == 1))
//		if(iMaxOrMin[j] == 1)
		{
			for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxOrMin[j])] / ( 2 * lMax)) ;i++)
			{	
				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxOrMin[j]) + i;

				*lpDst = (unsigned char)0;
			}
			int q8=0;
		}
		else if(iMaxOrMin[j] > 0)
		{
			for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxOrMin[j])] / ( 2 * lMax)) ;i++)
			{	
				// 指向目标图像倒数第j行,第i个象素的指针			
				if((int)fmod(i,5)==0)
				{
					lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxOrMin[j]) + i;
					*lpDst = (unsigned char)0;
				}
			}
			int q9=0;
		}
	}

			
	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	delete []lTotalNumber;
	delete []lBlackNumber;
	delete []lSmooth1;
	delete []lSmooth2;
	delete []lDiffer;
	delete []iMaxOrMin;
	// 返回
	return TRUE;
}

BOOL WINAPI HDifferProjDIB3(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	int iExtrem,iExtrem2,iBottom1,iBottom2;

	long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber);
	long (*lDiffer);
	int  (*iMaxOrMin),(*iMaxAndMin);  

	lTotalNumber = new long[1000];//平滑模板
	lSmooth1 = new long[1000];
	lSmooth2 = new long[1000];
	lBlackNumber = new long[1000];
	lDiffer = new long[1000];
	iMaxOrMin = new int[1000];
	iMaxAndMin = new int[1000];
	long lMax;

	float fAlpha;

	fAlpha = 0.2;

	//像素值
	unsigned char pixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(i = 0; i < 1000; i++)
	{
		lTotalNumber[i] = 0;
		lBlackNumber[i] = 0;
		lSmooth1[i] = 0; 
		lSmooth2[i] = 0;
		lDiffer[i] = 0;
		iMaxOrMin[i] = 0;
		iMaxAndMin[i] = 0;
	}

	for (j = 0;j < lHeight ;j++)
	{
		for(i = 0;i < lWidth ;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;
	
			lTotalNumber[j] += pixel;
		}
	}
	// 求最大值
	lMax = 0;
	for(i=0;i<1000;i++)
	{
		if(lTotalNumber[i] >= lMax)
		{
			lMax = lTotalNumber[i];
		}
	}

	// 平滑
	lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax));
	lSmooth2[0] = lSmooth1[0];
    lBlackNumber[0] = lSmooth2[0];

	// 一次平滑
	for (j = 1;j < lHeight ;j++)
	{
//		lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax));
		lSmooth1[j] = lTotalNumber[j];
		lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]);
//		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
	}
	// 二次平滑
	for (j = 1;j < lHeight ;j++)
	{
		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
		lDiffer[j - 1] = lBlackNumber[j] - lBlackNumber[j - 1];
	}

	// 判断极值
	iExtrem = 1;
	for (j = 1;j < lHeight ;j++)
	{
		// 极大值
//		if((lBlackNumber[j-1]>lBlackNumber[j])&&(lBlackNumber[j+1]>=lBlackNumber[j]))
		if((lDiffer[j - 1] > 0)&&(lDiffer[j] <= 0))
		{
			iMaxOrMin[iExtrem] = j;
			iExtrem++;
		}
		// 极小值
//		else if((lBlackNumber[j-1]<=lBlackNumber[j])&&(lBlackNumber[j+1]<lBlackNumber[j]))
		else if((lDiffer[j - 1] < 0)&&(lDiffer[j] >= 0))
		{
			iMaxOrMin[iExtrem] = -1 * j;
			iExtrem++;
		}
	}

	// 提取有效波谷
	i=iExtrem-1;
	j=iExtrem-2;
	int a1,a2,a3,a4,a5,a6,b1,b2,b3;
	do
	{
		int q1 =0;
		a1 = iMaxOrMin[i];
		a2 = iMaxOrMin[j];
		a3 = iMaxOrMin[j-1];
		if(i<iExtrem-2)
		{
			a4=iMaxOrMin[i+1];
			a5=iMaxOrMin[i+2];
		}
		b1 = lBlackNumber[abs(iMaxOrMin[i])];
		b2 = lBlackNumber[abs(iMaxOrMin[j])];
		b3 = lBlackNumber[abs(iMaxOrMin[j-1])];



		// 前为极大值,后为极大值
		if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] )
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;
				j = j - 1;
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i - 1;
			}
		}
		// 前为极小值,后为极小值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j])])
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;//j=j+1
				j = j - 1;//
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i - 1;
			}
		}
		// 前为极大值,后为极小值		 
		else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) 
			&& (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  >= lBlackNumber[abs(iMaxOrMin[j - 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j - 1] = 0;
				j = j - 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j - 1;
				j = i - 1;
			}
		}
		// 前为极小值,后为极大值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0)
			     && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j - 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j - 1] = 0;
				j = j - 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j - 1;
				j = i - 1;
			}
		}

		else
		{
			i = j;
			j = j - 1;
		}


	}while( j > 1);

	// 对波谷进一步提取

	iExtrem2=1;
	for (j = 1;j < iExtrem ;j++)
	{
		if((iMaxOrMin[j] != 0)&&(-iMaxOrMin[j]<3000))
		{
			iMaxAndMin[iExtrem2] = iMaxOrMin[j];
			iExtrem2++;
		}
	}
		int q2=0;


	for(j=1;j < iExtrem2;j++)
	{
		if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j + 1] > 0)&&(iMaxAndMin[j + 2] < 0))
		{
			// 车牌区域差影区应满足的条件
			if( (abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) >15)
			  &&(abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) <80)
			  &&(abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j+1])]) >60)
			  &&(abs(lBlackNumber[abs(iMaxAndMin[j+1])] - lBlackNumber[abs(iMaxAndMin[j+2])]) >60) )
			{;}
			else
			{
				iMaxAndMin[j] = 0;
			}
		}
	}

	for(j=1;j < iExtrem2;j++)
	{
		if((iMaxAndMin[j] > 0)&&(iMaxAndMin[j + 1] < 0)&&(iMaxAndMin[j + 2] > 0))
		{
			// 车牌区域差影区应满足的条件
			if( (abs(iMaxAndMin[j] + iMaxAndMin[j + 1]) <10)
			  &&(abs(iMaxAndMin[j + 1] + iMaxAndMin[j + 2]) <10) )
//			  &&( (abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j - 1])]) < 10)
//			     ||(abs(lBlackNumber[abs(iMaxAndMin[j - 1])] - lBlackNumber[abs(iMaxAndMin[j - 2])]) <10)))
			{
				iMaxAndMin[j + 1] = 0;
			}
			else
			{;}
		}
	}

/*
	for(j=iExtrem2;j > 1;j--)
	{
		if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j - 1] > 0))
//		 ||(iMaxAndMin[j] > 0)&&(iMaxAndMin[j - 1] < 0))
		{
			// 车牌区域差影区应满足的条件

			if(
				( 
				 abs 
				   ( 
				    lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j-1])]
				   )  
				   >100
				)&&
				(
				 abs
				  (
				   iMaxAndMin[j] + iMaxAndMin[j - 1]
				  )
				  >10
				 )
				)

			{;}
			else
			{
				iMaxAndMin[j] = 0;
				iMaxAndMin[j-1] = 0;
			}
		}
	}
*/
    iBottom1=0;
	iBottom2=0;
/*	for(j=iExtrem2;j > 1;)
	{
		if((iMaxAndMin[j] < 0)&&(iBottom2=0))
		{
			iBottom1 = iMaxAndMin[j];
			iBottom2=1;
			j--;
		}
		else if((iMaxAndMin[j] < 0)&&(iBottom1 != 0))
		{
			iBottom2 = iMaxAndMin[j];
				if( (abs(iBottom1 - iBottom2) >20)
				  &&(abs(iBottom1 - iBottom2) <60))
				{;}
				else
				{
					iMaxAndMin[j] = 0;
				}
			iBottom2=0;
			j--;
		}
		else
		{
			j--;
		}
	}
*/
	int q3=0;	
	// 赋值
	for (j = 1;j < iExtrem2 ;j++)
	{
		int q5=0;
		a1=iMaxAndMin[j];
		a2=abs(iMaxAndMin[j]);
		a3=lBlackNumber[abs(iMaxAndMin[j])];
		a4=0;
		if(iMaxAndMin[j] < 0)//||(iMaxOrMin[j] == 1))
//		if(iMaxOrMin[j] == 1)
		{
			for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++)
			{	
				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i;

				*lpDst = (unsigned char)0;
			}
			int q8=0;
		}
		else if(iMaxAndMin[j] > 0)
		{
			for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++)
			{	
				// 指向目标图像倒数第j行,第i个象素的指针
				if((int)fmod(i,5)==0)
				{
					lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i;
					*lpDst = (unsigned char)0;
				}
			}
			int q9=0;
		}
	}

			
	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	delete []lTotalNumber;
	delete []lBlackNumber;
	delete []lSmooth1;
	delete []lSmooth2;
	delete []lDiffer;
	delete []iMaxOrMin;
	delete []iMaxAndMin;
	// 返回
	return TRUE;
}

int* WINAPI HDifferProjDIB4(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	int* pPlateLine;
	int iPlateLine[40];

	//循环变量
	long i;
	long j;

	int iExtrem,iExtrem2,iExtrem3,iBottom1,iBottom2;

	long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber);
	long (*lDiffer);
	int  (*iMaxOrMin),(*iMaxAndMin);  

	lTotalNumber = new long[1000];//平滑模板
	lSmooth1 = new long[1000];
	lSmooth2 = new long[1000];
	lBlackNumber = new long[1000];
	lDiffer = new long[1000];
	iMaxOrMin = new int[1000];
	iMaxAndMin = new int[1000];
	long lMax;

	float fAlpha;

	fAlpha = 0.2;

	//像素值
	unsigned char pixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(i = 0; i < 1000; i++)
	{
		lTotalNumber[i] = 0;
		lBlackNumber[i] = 0;
		lSmooth1[i] = 0; 
		lSmooth2[i] = 0;
		lDiffer[i] = 0;
		iMaxOrMin[i] = 0;
		iMaxAndMin[i] = 0;
	}

	for (j = 0;j < lHeight ;j++)
	{
		for(i = 0;i < lWidth ;i++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;
	
			lTotalNumber[j] += pixel;
		}
	}
	// 求最大值
	lMax = 0;
	for(i=0;i<1000;i++)
	{
		if(lTotalNumber[i] >= lMax)
		{
			lMax = lTotalNumber[i];
		}
	}

	// 平滑
	lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax));
	lSmooth2[0] = lSmooth1[0];
    lBlackNumber[0] = lSmooth2[0];

	// 一次平滑
	for (j = 1;j < lHeight ;j++)
	{
//		lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax));
		lSmooth1[j] = lTotalNumber[j];
		lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]);
//		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
	}
	// 二次平滑
	for (j = 1;j < lHeight ;j++)
	{
		lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]);
		lDiffer[j - 1] = lBlackNumber[j] - lBlackNumber[j - 1];
	}

	// 判断极值
	iExtrem = 1;
	for (j = 1;j < lHeight ;j++)
	{
		// 极大值
//		if((lBlackNumber[j-1]>lBlackNumber[j])&&(lBlackNumber[j+1]>=lBlackNumber[j]))
		if((lDiffer[j - 1] > 0)&&(lDiffer[j] <= 0))
		{
			iMaxOrMin[iExtrem] = j;
			iExtrem++;
		}
		// 极小值
//		else if((lBlackNumber[j-1]<=lBlackNumber[j])&&(lBlackNumber[j+1]<lBlackNumber[j]))
		else if((lDiffer[j - 1] < 0)&&(lDiffer[j] >= 0))
		{
			iMaxOrMin[iExtrem] = -1 * j;
			iExtrem++;
		}
	}

	// 提取有效波谷
	i=iExtrem-1;
	j=iExtrem-2;
	int a1,a2,a3,a4,a5,a6,b1,b2,b3;
	do
	{
		int q1 =0;
		a1 = iMaxOrMin[i];
		a2 = iMaxOrMin[j];
		a3 = iMaxOrMin[j-1];
		if(i<iExtrem-2)
		{
			a4=iMaxOrMin[i+1];
			a5=iMaxOrMin[i+2];
		}
		b1 = lBlackNumber[abs(iMaxOrMin[i])];
		b2 = lBlackNumber[abs(iMaxOrMin[j])];
		b3 = lBlackNumber[abs(iMaxOrMin[j-1])];



		// 前为极大值,后为极大值
		if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] )
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;
				j = j - 1;
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i - 1;
			}
		}
		// 前为极小值,后为极小值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j])])
			{
				iMaxOrMin[j] = 0;
				//i = j + 1;//j=j+1
				j = j - 1;//
			}
			else
			{
				iMaxOrMin[i] = 0;
				i = j;
				j = i - 1;
			}
		}
		// 前为极大值,后为极小值		 
		else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) 
			&& (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  >= lBlackNumber[abs(iMaxOrMin[j - 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j - 1] = 0;
				j = j - 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j - 1;
				j = i - 1;
			}
		}
		// 前为极小值,后为极大值
		else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0)
			     && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16  ))
		{
			if(lBlackNumber[abs(iMaxOrMin[i])]  <= lBlackNumber[abs(iMaxOrMin[j - 1])] )
			{
				iMaxOrMin[j] = 0;
				iMaxOrMin[j - 1] = 0;
				j = j - 2;
			}
			else
			{
				iMaxOrMin[i] = 0;
				iMaxOrMin[j] = 0;
				i = j - 1;
				j = i - 1;
			}
		}

		else
		{
			i = j;
			j = j - 1;
		}


	}while( j > 1);

	// 对波谷进一步提取

	iExtrem2=1;
	for (j = 1;j < iExtrem ;j++)
	{
		if((iMaxOrMin[j] != 0)&&(-iMaxOrMin[j]<3000))
		{
			iMaxAndMin[iExtrem2] = iMaxOrMin[j];
			iExtrem2++;
		}
	}



	for(j=1;j < iExtrem2;j++)
	{
		if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j + 1] > 0)&&(iMaxAndMin[j + 2] < 0))
		{
			// 车牌区域差影区应满足的条件
			if( (abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) >15)
			  &&(abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) <80)
			  &&(abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j+1])]) >60)
			  &&(abs(lBlackNumber[abs(iMaxAndMin[j+1])] - lBlackNumber[abs(iMaxAndMin[j+2])]) >60) )
			{;}
			else
			{
				iMaxAndMin[j] = 0;
			}
		}
	}

	for(j=1;j < iExtrem2;j++)
	{
		if((iMaxAndMin[j] > 0)&&(iMaxAndMin[j + 1] < 0)&&(iMaxAndMin[j + 2] > 0))
		{
			// 车牌区域差影区应满足的条件
			if( (abs(iMaxAndMin[j] + iMaxAndMin[j + 1]) <10)
			  &&(abs(iMaxAndMin[j + 1] + iMaxAndMin[j + 2]) <10) )
//			  &&( (abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j - 1])]) < 10)
//			     ||(abs(lBlackNumber[abs(iMaxAndMin[j - 1])] - lBlackNumber[abs(iMaxAndMin[j - 2])]) <10)))
			{
				iMaxAndMin[j + 1] = 0;
			}
			else
			{;}
		}
	}

	iExtrem3=1;
	for (j = 1;j < iExtrem2-1 ;j++)
	{
		if(iMaxAndMin[j] < 0)
		{
			int q2=0;
			iMaxAndMin[iExtrem3] = iMaxAndMin[j];
			iExtrem3++;
			int q3=0;	
		}
	}

	for(j=iExtrem3-1;j > 1;j--)
	{
		// 两波谷位置之差小于20行
		if( abs(iMaxAndMin[j] - iMaxAndMin[j - 1]) <20)
		{
			iMaxAndMin[j] = 0;
		}
	}

/*	for(j=iExtrem2;j > 1;j--)
	{
		if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j - 1] > 0))
//		 ||(iMaxAndMin[j] > 0)&&(iMaxAndMin[j - 1] < 0))
		{
			// 车牌区域差影区应满足的条件

			if(
				( 
				 abs 
				   ( 
				    lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j-1])]
				   )  
				   >100
				)&&
				(
				 abs
				  (
				   iMaxAndMin[j] + iMaxAndMin[j - 1]
				  )
				  >10
				 )
				)

			{;}
			else
			{
				iMaxAndMin[j] = 0;
				iMaxAndMin[j-1] = 0;
			}
		}
	}
*/
    iBottom1=0;
	iBottom2=0;
/*	for(j=iExtrem2;j > 1;)
	{
		if((iMaxAndMin[j] < 0)&&(iBottom2=0))
		{
			iBottom1 = iMaxAndMin[j];
			iBottom2=1;
			j--;
		}
		else if((iMaxAndMin[j] < 0)&&(iBottom1 != 0))
		{
			iBottom2 = iMaxAndMin[j];
				if( (abs(iBottom1 - iBottom2) >20)
				  &&(abs(iBottom1 - iBottom2) <60))
				{;}
				else
				{
					iMaxAndMin[j] = 0;
				}
			iBottom2=0;
			j--;
		}
		else
		{
			j--;
		}
	}
*/

	// 赋值
	for (j = 1;j < iExtrem3 ;j++)
	{
//		int q5=0;
//		a1=iMaxAndMin[j];
//		a2=abs(iMaxAndMin[j]);
//		a3=lBlackNumber[abs(iMaxAndMin[j])];
//		a4=0;
		if(iMaxAndMin[j] < 0)//||(iMaxOrMin[j] == 1))
//		if(iMaxOrMin[j] == 1)
		{
			for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++)
			{	
				// 指向目标图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i;

				*lpDst = (unsigned char)0;
			}
			int q8=0;
		}
		else if(iMaxAndMin[j] > 0)
		{
			for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++)
			{	
				// 指向目标图像倒数第j行,第i个象素的指针
				if((int)fmod(i,5)==0)
				{
					lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i;
					*lpDst = (unsigned char)0;
				}
			}

		}
	}

	for(i=0;i<40;i++)
	{
		iPlateLine[i]=0;
	}

	int iLineNum=0;
	for (j = 1;j < iExtrem3;j++)
	{
		if(iMaxAndMin[j] < 0)
		{
			iPlateLine[iLineNum] = iMaxAndMin[j];
			iLineNum++;
		}
	}

	pPlateLine = &iPlateLine[0];
	int q9=0;
	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	delete []lTotalNumber;
	delete []lBlackNumber;
	delete []lSmooth1;
	delete []lSmooth2;
	delete []lDiffer;
	delete []iMaxOrMin;
	delete []iMaxAndMin;
	// 返回
	return pPlateLine;
}

/*************************************************************************
 *
 * 函数名称:
 *   VprojectDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对两幅图像进行垂直投影运算。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI VprojectDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	//图像中每行内的黑点个数
	long lBlackNumber;

	//像素值
	unsigned char pixel;

	// 图像每行的字节数
	LONG lLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for (i = 0;i < lWidth ;i++)
	{
		lBlackNumber = 0;
		for(j = 0;j < lHeight ;j++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
	
			pixel = (unsigned char)*lpSrc;

			if (pixel != 255 && pixel != 0)
			{
				return false;
			}
			if(pixel == 0)
			{
				lBlackNumber++;
			}
		}
		for(j = 0;j < lBlackNumber ;j++)
		{	
			// 指向目标图像倒数第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;

			*lpDst = (unsigned char)0;
		}		
	}

			
	// 复制投影图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   TemplateMatchDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LPSTR lpDIBBitsBK  - 指向背景DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *   LONG  lTemplateWidth       - 模板图像宽度(象素数)
 *   LONG  lTemplateHeight      - 模板图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对图像进行模板匹配运算。
 * 
 * 要求目标图像为255个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI TemplateMatchDIB (LPSTR lpDIBBits, LPSTR lpTemplateDIBBits, LONG lWidth, LONG lHeight,
							  LONG lTemplateWidth,LONG lTemplateHeight)
{	
	// 指向源图像的指针
	LPSTR	lpSrc,lpTemplateSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;
	long m;
	long n;

	//中间结果
	double dSigmaST;
	double dSigmaS;
	double dSigmaT;

	//相似性测度
	double R;

	//最大相似性测度
	double MaxR;

	//最大相似性出现位置
	long lMaxWidth;
	long lMaxHeight;

	//像素值
	unsigned char pixel;
	unsigned char templatepixel;

	// 图像每行的字节数
	LONG lLineBytes,lTemplateLineBytes;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	lTemplateLineBytes = WIDTHBYTES(lTemplateWidth * 8);

	//计算dSigmaT
	dSigmaT = 0;
	for (n = 0;n < lTemplateHeight ;n++)
	{
		for(m = 0;m < lTemplateWidth ;m++)
		{
			// 指向模板图像倒数第j行,第i个象素的指针			
			lpTemplateSrc = (char *)lpTemplateDIBBits + lTemplateLineBytes * n + m;
			templatepixel = (unsigned char)*lpTemplateSrc;
			dSigmaT += (double)templatepixel*templatepixel;
		}
	}

	//找到图像中最大相似性的出现位置
	MaxR = 0.0;
	for (j = 0;j < lHeight - lTemplateHeight +1 ;j++)
	{
		for(i = 0;i < lWidth - lTemplateWidth + 1;i++)
		{
			dSigmaST = 0;
			dSigmaS = 0;
	
			for (n = 0;n < lTemplateHeight ;n++)
			{
				for(m = 0;m < lTemplateWidth ;m++)
				{
					// 指向源图像倒数第j+n行,第i+m个象素的指针			
					lpSrc  = (char *)lpDIBBits + lLineBytes * (j+n) + (i+m);
			
					// 指向模板图像倒数第n行,第m个象素的指针			
					lpTemplateSrc  = (char *)lpTemplateDIBBits + lTemplateLineBytes * n + m;

					pixel = (unsigned char)*lpSrc;
					templatepixel = (unsigned char)*lpTemplateSrc;

					dSigmaS += (double)pixel*pixel;
					dSigmaST += (double)pixel*templatepixel;
				}
			}
			//计算相似性
			R = dSigmaST / ( sqrt(dSigmaS)*sqrt(dSigmaT));
			//与最大相似性比较
			if (R > MaxR)
			{
				MaxR = R;
				lMaxWidth = i;
				lMaxHeight = j;
			}
		}
	}

	//将最大相似性出现区域部分复制到目标图像
	for (n = 0;n < lTemplateHeight ;n++)
	{
		for(m = 0;m < lTemplateWidth ;m++)
		{
			lpTemplateSrc = (char *)lpTemplateDIBBits + lTemplateLineBytes * n + m;
			lpDst = (char *)lpNewDIBBits + lLineBytes * (n+lMaxHeight) + (m+lMaxWidth);
			*lpDst = *lpTemplateSrc;
		}
	}
	
	// 复制图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}



BOOL WINAPI NUMBERSCANLINE(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	return TRUE;
}

BOOL WINAPI NUMBERSCANROW(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
	return TRUE;
}

int  WINAPI Distance13(LONG iWidth, LONG iHeight, int ix, int iy)
{
	// 图像点x方向的坐标
	int x = ix;
	// 图像点y方向的坐标
	int y = iy;
	// 循环变量
	LONG i;
	// 求最小距离时用到的变量
	float fMin;
	// 该图像点对应的段的标号
	int iSect;
	// 13段计算距离的参考坐标数组
//	int iRefer[13][2]={0,0,};
	// 图像点到13段的距离数组
	float fDistance[14];

	// 初始化距离
	for(i = 0; i < 14; i++)
	{
		fDistance[i] = 100.0;
	}

	// 计算图像点到各段的距离
	fDistance[1] = x * x;
	fDistance[2] = (x - 20) * (x - 20);
	fDistance[3] = (x - 39) * (x - 39);
	if(x < 20)
	{
		fDistance[4] = y * y;
		fDistance[5] =  100.0;
		fDistance[6] = (y - 10) * (y - 10);
		fDistance[7] =  100.0;
		fDistance[8] = (y - 20) * (y - 20);
		fDistance[9] =  100.0;
		fDistance[10] = x * x / 4.0 + y * y - x * y;
		fDistance[11] = 100.0;
		fDistance[12] = (8.0 - x / 5.0 - 2.0 * y / 5.0) * (8 - x / 5.0 - 2.0 * y / 5.0) +
			            (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0) * (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0);
		fDistance[13] = 100.0;
	}
	else
	{
		fDistance[4] =  100.0 ;
		fDistance[5] = y * y  ;
		fDistance[6] =  100.0 ;
		fDistance[7] = (y - 10) * (y - 10);
		fDistance[8] =  100.0 ;
		fDistance[9] = (y - 20) * (y - 20);
		fDistance[10] = 100.0;
		fDistance[11] = (8.0 - x / 5.0 - 2.0 * y / 5.0) * (8 - x / 5.0 - 2.0 * y / 5.0) +
			            (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0) * (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0);
		fDistance[12] = 100.0;
		fDistance[13] = x * x / 4.0 + y * y - x * y;
	}

	// 求最小距离
	iSect = 1;
	fMin = fDistance[1];
	for(i = 2; i < 14; i++)
	{
		if( fDistance[i] <= fMin)
		{
			fMin = fDistance[i];
			iSect = i;
		}
	}
	
	return iSect;
}

int  WINAPI Distance16(LONG iWidth, LONG iHeight, int ix, int iy)
{
	// 图像点x方向的坐标
	int x = ix;
	// 图像点y方向的坐标
	int y = iy;
	// 循环变量
	LONG i;
	// 求最小距离时用到的变量
	float fMin;
	// 该图像点对应的段的标号
	int iSect;

	// 图像点到13段的距离数组
	float fDistance[17];

	// 初始化距离
	for(i = 0; i < 17; i++)
	{
		fDistance[i] = 1000.0;
	}

	// 计算图像点到各段的距离,x是垂直方向,y是水平方向
	float d1,d2,d3,d4,d5,d6,d7,d8;

	// d1:到1、2的距离的平方
	d1 = y * y;
	// d2:到3、4的距离的平方
	d2 = (y-20) * (y-20);
	// d3:到5、6的距离的平方
	d3 = (y-40) * (y-40);
	// d4:到7、8的距离的平方
	d4 = x * x;
	// d5:到9、10的距离的平方
	d5 = (x-10) * (x-10);
	// d6:到11、12的距离的平方
	d6 = (x-20) * (x-20);
	// d7:到13、16的距离的平方
	d7 = (y-2*x)*(y-2*x)*(0.5*y-x)*(0.5*y-x)/( ( y-2*x)*(y-2*x) + (0.5*y-x)*(0.5*y-x) );
	// d8:到14、15的距离的平方
	d8 = (y+2*x-40)*(y+2*x-40)*(0.5*y+x-20)*(0.5*y+x-20)/( (y+2*x-40)*(y+2*x-40) + (0.5*y+x-20)*(0.5*y+x-20) );

	// 字符左下的子区域
	if( (x < 10) && (y < 20) )
	{
		fDistance[1] = d1;
		fDistance[3] = d2;
	    fDistance[7] = d4;
		fDistance[9] = d5;
		fDistance[13] = d7;
	}
	// 字符右下的子区域
	else if((x >= 10) && (y < 20))
	{
		fDistance[2] = d1;
		fDistance[4] = d2;
		fDistance[9] = d5;
		fDistance[11] = d6;
		fDistance[15] = d8;
	}
	// 字符左上的子区域
	else if((x < 10) && (y >= 20))
	{
		fDistance[3] = d2;
	    fDistance[5] = d3;
		fDistance[8] = d4;
		fDistance[10] = d5;
		fDistance[14] = d8;
	}
	// 字符右上的子区域
	else if( (x >= 10) && (y >= 20) )
	{
		fDistance[4] = d2;
		fDistance[6] = d3;
		fDistance[10] = d5;
		fDistance[12] = d6;
		fDistance[16] = d7;
	}
 
	else
	{
		AfxMessageBox("坐标错误!");
		return NULL;
	}

	// 求最小距离
	iSect = 1;
	fMin = fDistance[1];
	for(i = 2; i < 17; i++)
	{
		if( fDistance[i] < fMin)
		{
			fMin = fDistance[i];
			iSect = i;
		}
	}
	
	return iSect;
}


float* WINAPI CharExtract13Sect(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{

	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	//循环变量
	long i;
	long lRow;
	long lLine;

	// 像素的灰度值
	unsigned char pixelvalue;

	// 13段投影码表
	float fCode13Sect[13];
	// 13段投影码表指针
	float* pCode13Sect;

	// 与图像点最近的段的标号
	int iSectNum;

	// 图像每行的字节数
	LONG lLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	// 初始化
	iSectNum = 0;

	for(i = 0; i < 13; i++)
	{
		fCode13Sect[i] = 0.0;
	}
	
	for (lRow = 0;lRow < lWidth ;lRow++)
	{
		for(lLine = 0;lLine < lHeight ;lLine++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow;
			pixelvalue = (unsigned char)*lpSrc;

			if (pixelvalue == 0)
			{
				iSectNum = Distance13(lWidth,lHeight,lLine,lRow) - 1;
				fCode13Sect[iSectNum] += 1.0;
			}
		}
	}

	// 码表归一化处理
	for(i = 0; i < 13; i++)
	{
		if(fCode13Sect[i] > 20.0)
		{
			fCode13Sect[i] = 20.0;
		}
		fCode13Sect[i] /= 20.0;
	}	

    pCode13Sect = &fCode13Sect[0];
	return pCode13Sect;

}

float* WINAPI CharExtract16Sect(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{

	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	//循环变量
	long i,j;
	long lRow;
	long lLine;

	// 像素的灰度值
	unsigned char pixelvalue;

	// 13段投影码表
	float fCode16Sect[6][16];
	// 13段投影码表指针
	float* pCode16Sect;

	// 与图像点最近的段的标号
	int iSectNum;

	int iCharNum;

	// 图像每行的字节数
	LONG lLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	// 初始化
	iSectNum = 0;
	iCharNum = 0;

	for(i = 0; i < 6; i++)
	{
		for(j = 0; j < 16; j++)
		{
			fCode16Sect[i][j] = 0.0;
		}

	}
	// 传一个有效象素提取特征
	int y;
	for (lRow = 20;lRow < lWidth ;lRow++)
	{
		iCharNum = (int)(lRow/20);
		y = lRow - 20 * iCharNum;
		int q8=0;
		for(lLine = 0;lLine < lHeight ;lLine++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow;
			pixelvalue = (unsigned char)*lpSrc;

			if (pixelvalue == 0)
			{
				iSectNum = Distance16(lWidth,lHeight,y,lLine) - 1;
				fCode16Sect[iCharNum-1][iSectNum] += 1.0;
				int q9=0;
			}
		}
	}
	TRACE("\n");
	// 码表归一化处理
	for(i = 0; i < 6; i++)
	{
		for(j = 0; j < 16; j++)
		{
			if(fCode16Sect[i][j] > 20.0)
			{
				fCode16Sect[i][j] = 20.0;
			}
			fCode16Sect[i][j] /= 20.0;
		}
	}	

    pCode16Sect = &fCode16Sect[0][0];

	return pCode16Sect;

}

// 用于提取单个字符的特征
float* WINAPI CharExtract16Sect2(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{

	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	//循环变量
	long i,j;
	long lRow;
	long lLine;

	// 像素的灰度值
	unsigned char pixelvalue;

	// 13段投影码表
	float fCode16Sect[16];
	// 13段投影码表指针
	float* pCode16Sect;

	// 与图像点最近的段的标号
	int iSectNum;

	// 图像每行的字节数
	LONG lLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	// 初始化
	iSectNum = 0;

	for(j = 0; j < 16; j++)
	{
		fCode16Sect[j] = 0.0;
	}
	// 传一个有效象素提取特征
	int y;
	for (lRow = 0;lRow < lWidth ;lRow++)
	{
		int q8=0;
		for(lLine = 0;lLine < lHeight ;lLine++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow;
			pixelvalue = (unsigned char)*lpSrc;

			if (pixelvalue == 0)
			{
				iSectNum = Distance16(lWidth,lHeight,lRow,lLine) - 1;
				fCode16Sect[iSectNum] += 1.0;
				int q9=0;
			}
		}
	}
	TRACE("\n");
	// 码表归一化处理
	for(j = 0; j < 16; j++)
	{
		if(fCode16Sect[j] > 20.0)
		{
			fCode16Sect[j] = 20.0;
		}
		fCode16Sect[j] /= 20.0;
	}	

    pCode16Sect = &fCode16Sect[0];

	return pCode16Sect;

}

unsigned char WINAPI DistanceStruct(float* pCodeStruct)
{
	// 字典特征向量
	float fDictionaryChar[10][16];

	// 待识字符特征向量
	float fWaitChar[16];

	// 存储10个距离
	float fDistance[16];

	// 存储识别结果
	unsigned char cRecoChar;

	// 临时变量,用以比较大小
	float fTemp;

	// 
	char *DictionaryDataFileName = "训练数据_微特征.dat ";

	//
	FILE *fpDictionaryData;	
	// 循环变量
	int i,j;

	if((fpDictionaryData = fopen(DictionaryDataFileName,"r"))==NULL)
	{
		AfxMessageBox("无法打开训练数据文件!\n   请确认文件路径!");
		return 0;
	}

	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 16; j++)
		{
			// 将训练数据读入训练数据数组中
			fscanf(fpDictionaryData,"%f",&fDictionaryChar[i][j]);
		}
	}
	// 关闭文件
	fclose(fpDictionaryData);

	// 传递数据
	for(i = 0; i < 16; i++)
	{
		fWaitChar[i] = *pCodeStruct;
		pCodeStruct++;
	}

	// 求16个距离
	for(i = 0; i < 10; i++)
	{
		fDistance[i] = 0.0;
		for(j = 0; j < 16; j++)
		{
			fDistance[i] = (fDictionaryChar[i][j] - fWaitChar[j]) * (fDictionaryChar[i][j] - fWaitChar[j]);
		}
	}

	// 求距离的最小值,判断识别字符
	fTemp = fDistance[1];
	cRecoChar = (unsigned char)0;

	for(i = 1; i < 10; i++)
	{
		if(fDistance[i] <= fTemp)
		{
			fTemp = fDistance[i];
			cRecoChar = (unsigned char)i;
		}
	}

	return cRecoChar;
}

float* WINAPI CharExtractStruct(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	//循环变量
	long i,j,k;
	long lRow;
	long lLine;

	// 像素的灰度值
	unsigned char pixelvalue;

	// 字符的微结构特征向量
	float fCodeStruct[16];

	float* pCodeStruct;

	// 存储待识字符信息
	int iImageData[20][40];

	// 12种微结构模板
	int iStruct[12][9] = {0,0,0,1,1,1,0,0,0,  // 水平 1
						  0,1,0,0,1,0,0,1,0,  // 垂直 2
						  0,0,1,0,1,0,1,0,0,  // 正斜线 3
						  1,0,0,0,1,0,0,0,1,  // 反斜线 4
						  0,1,0,0,1,0,1,0,0,  // 垂直 2
						  0,1,0,0,1,0,0,0,1,  // 垂直 2
					      1,0,0,0,1,0,0,1,0,  // 垂直 2
						  0,0,1,0,1,0,0,1,0,  // 垂直 2
						  0,0,1,1,1,0,0,0,0,  // 正斜线 3
						  0,0,0,1,1,0,0,0,1,  // 反斜线 4
						  1,0,0,0,1,1,0,0,0,  // 反斜线 4
						  0,0,0,0,1,1,1,0,0}; // 正斜线 3

	// 临时变量
	float fTemp;
	int   iTemp;

	// 图像每行的字节数
	LONG lLineBytes;

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(i = 0; i < 16; i++)
	{
		fCodeStruct[i] = 0.0;
	}

	// 读取图像数据
	for (lRow = 0;lRow < lHeight ;lRow++)
	{
		for(lLine = 0;lLine < lWidth ;lLine++)
		{
			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow;
			pixelvalue = (unsigned char)*lpSrc;

			if(pixelvalue == 0)
			{
				iImageData[lLine][lRow] = 1;
			}

			else 
			{
				iImageData[lLine][lRow] = 0;
			}
		}
	}

	// 左上角子区域
	for(i = 1; i < 9; i++)
	{
		for(j = 1; j < 19; j++)
		{
			iTemp = 0;
			// 对12个模板进行匹配
			for(k = 0; k < 12; k++ )
			{
				iTemp = iImageData[i-1][j-1]*iStruct[k][0]+
						iImageData[i][j-1]*iStruct[k][1]+
						iImageData[i+1][j-1]*iStruct[k][2]+
						iImageData[i-1][j]*iStruct[k][3]+
						iImageData[i][j]*iStruct[k][4]+
						iImageData[i+1][j]*iStruct[k][5]+
						iImageData[i-1][j+1]*iStruct[k][6]+
						iImageData[i][j+1]*iStruct[k][7]+
						iImageData[i+1][i+1]*iStruct[k][8];

				if(iTemp == 3)
				{
					if(k == 0)
						fCodeStruct[0] ++;
					else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7))
						fCodeStruct[1] ++;
					else if((k==2)||(k==8)||(k==11))
						fCodeStruct[2] ++;
					else if((k==3)||(k==9)||(k==10))
						fCodeStruct[3] ++;
					break;
				}
			}
		}
	}

	// 右上角子区域
	for(i = 11; i < 19; i++)
	{
		for(j = 1; j < 19; j++)
		{
			iTemp = 0;
			// 对12个模板进行匹配
			for(k = 0; k < 12; k++ )
			{
				iTemp = iImageData[i-1][j-1]*iStruct[k][0]+
						iImageData[i][j-1]*iStruct[k][1]+
						iImageData[i+1][j-1]*iStruct[k][2]+
						iImageData[i-1][j]*iStruct[k][3]+
						iImageData[i][j]*iStruct[k][4]+
						iImageData[i+1][j]*iStruct[k][5]+
						iImageData[i-1][j+1]*iStruct[k][6]+
						iImageData[i][j+1]*iStruct[k][7]+
						iImageData[i+1][i+1]*iStruct[k][8];

				if(iTemp == 3)
				{
					if(k == 0)
						fCodeStruct[4] ++;
					else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7))
						fCodeStruct[5] ++;
					else if((k==2)||(k==8)||(k==11))
						fCodeStruct[6] ++;
					else if((k==3)||(k==9)||(k==10))
						fCodeStruct[7] ++;
					break;
				}
			}
		}
	}

	// 左下角子区域
	for(i = 1; i < 9; i++)
	{
		for(j = 21; j < 39; j++)
		{
			iTemp = 0;
			// 对12个模板进行匹配
			for(k = 0; k < 12; k++ )
			{
				iTemp = iImageData[i-1][j-1]*iStruct[k][0]+
						iImageData[i][j-1]*iStruct[k][1]+
						iImageData[i+1][j-1]*iStruct[k][2]+
						iImageData[i-1][j]*iStruct[k][3]+
						iImageData[i][j]*iStruct[k][4]+
						iImageData[i+1][j]*iStruct[k][5]+
						iImageData[i-1][j+1]*iStruct[k][6]+
						iImageData[i][j+1]*iStruct[k][7]+
						iImageData[i+1][i+1]*iStruct[k][8];

				if(iTemp == 3)
				{
					if(k == 0)
						fCodeStruct[8] ++;
					else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7))
						fCodeStruct[9] ++;
					else if((k==2)||(k==8)||(k==11))
						fCodeStruct[10] ++;
					else if((k==3)||(k==9)||(k==10))
						fCodeStruct[11] ++;
					break;
				}
			}
		}
	}

	// 右下角子区域
	for(i = 11; i < 19; i++)
	{
		for(j = 21; j < 39; j++)
		{
			iTemp = 0;
			// 对12个模板进行匹配
			for(k = 0; k < 12; k++ )
			{
				iTemp = iImageData[i-1][j-1]*iStruct[k][0]+
						iImageData[i][j-1]*iStruct[k][1]+
						iImageData[i+1][j-1]*iStruct[k][2]+
						iImageData[i-1][j]*iStruct[k][3]+
						iImageData[i][j]*iStruct[k][4]+
						iImageData[i+1][j]*iStruct[k][5]+
						iImageData[i-1][j+1]*iStruct[k][6]+
						iImageData[i][j+1]*iStruct[k][7]+
						iImageData[i+1][i+1]*iStruct[k][8];

				if(iTemp == 3)
				{
					if(k == 0)
						fCodeStruct[12] ++;
					else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7))
						fCodeStruct[13] ++;
					else if((k==2)||(k==8)||(k==11))
						fCodeStruct[14] ++;
					else if((k==3)||(k==9)||(k==10))
						fCodeStruct[15] ++;
					break;
				}
			}
		}
	}

	fTemp = fCodeStruct[0];

	// 求最大值
	for(i = 1; i < 16; i++)
	{
		if(fCodeStruct[i] >= fTemp)
		{
			fTemp = fCodeStruct[i];
		}
	}

	// 码表归一化处理
	for(i = 0; i < 16; i++)
	{
		fCodeStruct[i] /= fTemp;
	}	

    pCodeStruct = &fCodeStruct[0];

	return pCodeStruct;
}

/*************************************************************************
 *
 * 函数名称:
 *   HoughDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对检测图像中的平行直线。如果图像中有两条平行的直线,则将这两条平行直线
 * 提取出来。
 * 
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/

BOOL WINAPI HoughDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
		
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向变换域的指针
	LPSTR   lpTrans;

	// 图像每行的字节数
	LONG lLineBytes;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//指向变换域的指针
	LPSTR	lpTransArea;
	HLOCAL	hTransArea;

	//变换域的尺寸
	int iMaxDist;
	int iMaxAngleNumber;

	//变换域的坐标
	int iDist;
	int iAngleNumber;

	//循环变量
	long i;
	long j;

	//像素值
	unsigned char pixel;

	//存储变换域中的两个最大值
	MaxValue MaxValue1;
	MaxValue MaxValue2;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);

	//计算变换域的尺寸
	//最大距离
	iMaxDist = (int) sqrt(lWidth*lWidth + lHeight*lHeight);

	//角度从0-180,每格2度
	iMaxAngleNumber = 90;

	//为变换域分配内存
	hTransArea = LocalAlloc(LHND, lWidth * lHeight * sizeof(int));

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpTransArea = (char * )LocalLock(hTransArea);
		
	// 初始化新分配的内存,设定初始值为0
	lpTrans = (char *)lpTransArea;
	memset(lpTrans, 0, lWidth * lHeight * sizeof(int));

	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth; i++)
		{

			// 指向源图像倒数第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lLineBytes * j + i;

			//取得当前指针处的像素值,注意要转换为unsigned char型
			pixel = (unsigned char)*lpSrc;

			//目标图像中含有0和255外的其它灰度值
			if(pixel != 255 && *lpSrc != 0)
				return FALSE;

			//如果是黑点,则在变换域的对应各点上加1
			if(pixel == 0)
			{
				//注意步长是2度
				for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++)
				{
					iDist = (int) fabs(i*cos(iAngleNumber*2*PI/180.0) + \
						j*sin(iAngleNumber*2*PI/180.0));
				
					//变换域的对应点上加1
					*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber) = \
						*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber) +1;
				}
			}
		
		}
	}
				
	//找到变换域中的两个最大值点
	MaxValue1.Value=0;
	MaxValue2.Value=0;
	
	//找到第一个最大值点
	for (iDist=0; iDist<iMaxDist;iDist++)
	{
		for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++)
		{
			if((int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber)>MaxValue1.Value)
			{
				MaxValue1.Value = (int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber);
				MaxValue1.Dist = iDist;
				MaxValue1.AngleNumber = iAngleNumber;
			}

		}
	}

	//将第一个最大值点附近清零
	for (iDist = -9;iDist < 10;iDist++)
	{
		for(iAngleNumber=-1; iAngleNumber<2; iAngleNumber++)
		{
			if(iDist+MaxValue1.Dist>=0 && iDist+MaxValue1.Dist<iMaxDist \
				&& iAngleNumber+MaxValue1.AngleNumber>=0 && iAngleNumber+MaxValue1.AngleNumber<=iMaxAngleNumber)
			{
				*(lpTransArea+(iDist+MaxValue1.Dist)*iMaxAngleNumber+\
					(iAngleNumber+MaxValue1.AngleNumber))=0;
			}
		}
	}

	//找到第二个最大值点
	for (iDist=0; iDist<iMaxDist;iDist++)
	{
		for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++)
		{
			if((int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber)>MaxValue2.Value)
			{
				MaxValue2.Value = (int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber);
				MaxValue2.Dist = iDist;
				MaxValue2.AngleNumber = iAngleNumber;
			}

		}
	}


	//判断两直线是否平行
	if(abs(MaxValue1.AngleNumber-MaxValue2.AngleNumber)<=2)
	{
		//两直线平行,在缓存图像中重绘这两条直线
		for(j = 0; j <lHeight; j++)
		{
			for(i = 0;i <lWidth; i++)
			{	

				// 指向缓存图像倒数第j行,第i个象素的指针			
				lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;	

				//如果该点在某一条平行直线上,则在缓存图像上将该点赋为黑

				//在第一条直线上
				iDist = (int) fabs(i*cos(MaxValue1.AngleNumber*2*PI/180.0) + \
							j*sin(MaxValue1.AngleNumber*2*PI/180.0));
				if (iDist == MaxValue1.Dist)
					*lpDst = (unsigned char)0;
			
				//在第二条直线上
				iDist = (int) fabs(i*cos(MaxValue2.AngleNumber*2*PI/180.0) + \
							j*sin(MaxValue2.AngleNumber*2*PI/180.0));
				if (iDist == MaxValue2.Dist)
					*lpDst = (unsigned char)0;
			}
		}
	}

	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 释放内存
	LocalUnlock(hTransArea);
	LocalFree(hTransArea);

	// 返回
	return TRUE;

}

/*************************************************************************
 *
 * 函数名称:
 *   DIBToPCX256()
 *
 * 参数:
 *   LPSTR lpDIB        - 指向DIB对象的指针
 *   CFile& file        - 要保存的文件
 *
 * 返回值:
 *   BOOL               - 成功返回True,否则返回False。
 *
 * 说明:
 *   该函数将指定的256色DIB对象保存为256色PCX文件。
 *
 *************************************************************************/
BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file)
{
	// 循环变量
	LONG	i;
	LONG	j;
	
	// DIB高度
	WORD	wHeight;
	
	// DIB宽度
	WORD	wWidth;
	
	// 中间变量
	BYTE	bChar1;
	BYTE	bChar2;
	
	// 指向源图像象素的指针
	BYTE *	lpSrc;
	
	// 指向编码后图像数据的指针
	BYTE *	lpDst;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 重复像素计数
	int		iCount;
	
	// 缓冲区已使用的字节数
	DWORD	dwBuffUsed;
	
	// 指向DIB象素指针
	LPSTR   lpDIBBits;
	
	// 获取DIB高度
	wHeight = (WORD) DIBHeight(lpDIB);
	
	// 获取DIB宽度
	wWidth  = (WORD) DIBWidth(lpDIB);
	
	// 找到DIB图像象素起始位置
	lpDIBBits = FindDIBBits(lpDIB);
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(wWidth * 8);
	
	
	//*************************************************************************
	// PCX文件头
	PCXHEADER pcxHdr;
	
	// 给文件头赋值
	
	// PCX标识码
	pcxHdr.bManufacturer = 0x0A;
	
	// PCX版本号
	pcxHdr.bVersion = 5;
	
	// PCX编码方式(1表示RLE编码)
	pcxHdr.bEncoding = 1;
	
	// 像素位数(256色为8位)
	pcxHdr.bBpp = 8;
	
	// 图像相对于屏幕的左上角X坐标(以像素为单位)
	pcxHdr.wLeft = 0;
	
	// 图像相对于屏幕的左上角Y坐标(以像素为单位)
	pcxHdr.wTop = 0;
	
	// 图像相对于屏幕的右下角X坐标(以像素为单位)
	pcxHdr.wRight = wWidth - 1;
	
	// 图像相对于屏幕的右下角Y坐标(以像素为单位)
	pcxHdr.wBottom = wHeight - 1;
	
	// 图像的水平分辨率
	pcxHdr.wXResolution = wWidth;
	
	// 图像的垂直分辨率
	pcxHdr.wYResolution = wHeight;
	
	// 调色板数据(对于256色PCX无意义,直接赋值为0)
	for (i = 0; i < 48; i ++)
	{
		pcxHdr.bPalette[i] = 0;
	}
	
	// 保留域,设定为0。
	pcxHdr.bReserved = 0;
	
	// 图像色彩平面数目(对于256色PCX设定为1)。
	pcxHdr.bPlanes = 1;
	
	// 图像的宽度(字节为单位),必须为偶数。
//	if ((wWidth & 1) == 0)
//	{
		pcxHdr.wLineBytes = wWidth;
//	}
//	else
//	{
//		pcxHdr.wLineBytes = wWidth + 1;
//	}
	
	// 图像调色板的类型,1表示彩色或者单色图像,2表示图像是灰度图。
	pcxHdr.wPaletteType = 1;
	
	// 制作该图像的屏幕宽度(像素为单位)
	pcxHdr.wSrcWidth = 0;
	
	// 制作该图像的屏幕高度(像素为单位)
	pcxHdr.wSrcDepth = 0;
	
	// 保留域,取值设定为0。
	for (i = 0; i < 54; i ++)
	{
		pcxHdr.bFiller[i] = 0;
	}
	
	// 写入文件头
	file.Write((LPSTR)&pcxHdr, sizeof(PCXHEADER));
	
	//*******************************************************************************
	// 开始编码
	
	// 开辟一片缓冲区(2被原始图像大小)以保存编码结果
	lpDst = new BYTE[wHeight * wWidth * 2];
	
	// 指明当前已经用了多少缓冲区(字节数)
	dwBuffUsed = 0;
	
	// 每行
	for (i = 0; i < wHeight; i++)
	{
		// 指向DIB第i行,第0个象素的指针
		lpSrc = (BYTE *)lpDIBBits + lLineBytes * (wHeight - 1 - i);
		
		// 给bChar1赋值
		bChar1 = *lpSrc;
		
		// 设置iCount为1
		iCount = 1;
		
		// 剩余列
		for (j = 1; j < wWidth; j ++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc++;
			
			// 读取下一个像素
			bChar2 = *lpSrc;
			
			// 判断是否和bChar1相同并且iCount < 63
			if ((bChar1 == bChar2) && (iCount < 63))
			{
				// 相同,计数加1
				iCount ++;
				
				// 继续读下一个
			}
			else
			{
				// 不同,或者iCount = 63
				
				// 写入缓冲区
				if ((iCount > 1) || (bChar1 >= 0xC0))
				{
					// 保存码长信息
					lpDst[dwBuffUsed] = iCount | 0xC0;
					
					// 保存bChar1
					lpDst[dwBuffUsed + 1] = bChar1;
					
					// 更新dwBuffUsed
					dwBuffUsed += 2;
				}
				else
				{
					// 直接保存该值
					lpDst[dwBuffUsed] = bChar1;
					
					// 更新dwBuffUsed
					dwBuffUsed ++;
				}
				
				// 重新给bChar1赋值
				bChar1 = bChar2;
				
				// 设置iCount为1
				iCount = 1;
			}
		}
		
		// 保存每行最后一部分编码
		if ((iCount > 1) || (bChar1 >= 0xC0))
		{
			// 保存码长信息
			lpDst[dwBuffUsed] = iCount | 0xC0;
			
			// 保存bChar1
			lpDst[dwBuffUsed + 1] = bChar1;
			
			// 更新dwBuffUsed
			dwBuffUsed += 2;
		}
		else
		{
			// 直接保存该值
			lpDst[dwBuffUsed] = bChar1;
			
			// 更新dwBuffUsed
			dwBuffUsed ++;
		}
	}
	
	// 写入编码结果
	file.WriteHuge((LPSTR)lpDst, dwBuffUsed);
	
	// 释放内存
	delete lpDst;
	
	//**************************************************************************
	// 写入调色板信息
	
	// 指向BITMAPINFO结构的指针(Win3.0)
	LPBITMAPINFO lpbmi;
	
	// 指向BITMAPCOREINFO结构的指针
	LPBITMAPCOREINFO lpbmc;
	
	// 表明是否是Win3.0 DIB的标记
	BOOL bWinStyleDIB;
	
	// 开辟一片缓冲区以保存调色板
	lpDst = new BYTE[769];
	
	// 调色板起始字节
	* lpDst = 0x0C;
	
	// 获取指向BITMAPINFO结构的指针(Win3.0)
	lpbmi = (LPBITMAPINFO)lpDIB;
	
	// 获取指向BITMAPCOREINFO结构的指针
	lpbmc = (LPBITMAPCOREINFO)lpDIB;
	
	// 判断是否是WIN3.0的DIB
	bWinStyleDIB = IS_WIN30_DIB(lpDIB);
	
	// 读取当前DIB调色板
	for (i = 0; i < 256; i ++)
	{
		if (bWinStyleDIB)
		{
			// 读取DIB调色板红色分量
			lpDst[i * 3 + 1] = lpbmi->bmiColors[i].rgbRed;
			
			// 读取DIB调色板绿色分量
			lpDst[i * 3 + 2] = lpbmi->bmiColors[i].rgbGreen;
			
			// 读取DIB调色板蓝色分量
			lpDst[i * 3 + 3] = lpbmi->bmiColors[i].rgbBlue;
		}
		else
		{
			// 读取DIB调色板红色分量
			lpDst[i * 3 + 1] = lpbmc->bmciColors[i].rgbtRed;
			
			// 读取DIB调色板绿色分量
			lpDst[i * 3 + 2] = lpbmc->bmciColors[i].rgbtGreen;
			
			// 读取DIB调色板蓝色分量
			lpDst[i * 3 + 3] = lpbmc->bmciColors[i].rgbtBlue;
		}
	}
	
	// 写入调色板信息
	file.Write((LPSTR)lpDst, 769);
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   ReadPCX256()
 *
 * 参数:
 *   CFile& file        - 要读取的文件
 *
 * 返回值:
 *   HDIB               - 成功返回DIB的句柄,否则返回NULL。
 *
 * 说明:
 *   该函数将读取指定的256色PCX文件。将读取的结果保存在一个未压缩
 * 编码的DIB对象中。
 *
 *************************************************************************/
HDIB WINAPI ReadPCX256(CFile& file)
{
	// PCX文件头
	PCXHEADER pcxHdr;
	
	// DIB大小(字节数)
	DWORD	dwDIBSize;
	
	// DIB句柄
	HDIB	hDIB;
	
	// DIB指针
	LPSTR	pDIB;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 重复像素计数
	int		iCount;
	
	// DIB高度
	WORD	wHeight;
	
	// DIB宽度
	WORD	wWidth;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 中间变量
	BYTE	bChar;
	
	// 指向源图像象素的指针
	BYTE *	lpSrc;
	
	// 指向编码后图像数据的指针
	BYTE *	lpDst;
	
	// 临时指针
	BYTE *	lpTemp;
	
	// 尝试读取PCX文件头
	if (file.Read((LPSTR)&pcxHdr, sizeof(PCXHEADER)) != sizeof(PCXHEADER))
	{
		// 大小不对,返回NULL。
		return NULL;
	}
	
	// 判断是否是256色PCX文件,检查第一个字节是否是0x0A,
	if ((pcxHdr.bManufacturer != 0x0A) || (pcxHdr.bBpp != 8) || (pcxHdr.bPlanes != 1))
	{
		// 非256色PCX文件,返回NULL。
		return NULL;
	}
	
	// 获取图像高度
	wHeight = pcxHdr.wBottom - pcxHdr.wTop + 1;
	
	// 获取图像宽度
	wWidth  = pcxHdr.wRight - pcxHdr.wLeft + 1;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(wWidth * 8);
	
	// 计算DIB长度(字节)
	dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + wHeight * lLineBytes;
	
	// 为DIB分配内存
	hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize);
	if (hDIB == 0)
	{
		// 内存分配失败,返回NULL。
		return NULL;
	}
	
	// 锁定
	pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
	
	// 指向BITMAPINFOHEADER的指针
	LPBITMAPINFOHEADER lpBI;
	
	// 赋值
	lpBI = (LPBITMAPINFOHEADER) pDIB;
	
	// 给lpBI成员赋值
	lpBI->biSize = 40;
	lpBI->biWidth = wWidth;
	lpBI->biHeight = wHeight;
	lpBI->biPlanes = 1;
	lpBI->biBitCount = 8;
	lpBI->biCompression = BI_RGB;
	lpBI->biSizeImage = wHeight * lLineBytes;
	lpBI->biXPelsPerMeter = pcxHdr.wXResolution;
	lpBI->biYPelsPerMeter = pcxHdr.wYResolution;
	lpBI->biClrUsed = 0;
	lpBI->biClrImportant = 0;
	
	// 分配内存以读取编码后的象素
	lpSrc = new BYTE[file.GetLength() - sizeof(PCXHEADER) - 769];
	lpTemp = lpSrc;
	
	// 读取编码后的象素
	if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCXHEADER) - 769) !=
		file.GetLength() - sizeof(PCXHEADER) - 769 )
	{
		// 大小不对。
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) hDIB);
		
		// 释放内存
		::GlobalFree((HGLOBAL) hDIB);
		
		// 返回NULL。
		return NULL;
	}
	
	// 计算DIB中像素位置
	lpDst = (BYTE *) FindDIBBits(pDIB);
	
	// 一行一行解码
	for (j = 0; j <wHeight; j++)
	{
		i = 0;
		while (i < wWidth)
		{
			// 读取一个字节
			bChar = *lpTemp;
			lpTemp++;
			
			if ((bChar & 0xC0) == 0xC0)
			{
				// 行程
				iCount = bChar & 0x3F;
				
				// 读取下一个字节
				bChar = *lpTemp;
				lpTemp++;
				
				// bChar重复iCount次保存
				memset(&lpDst[(wHeight - j - 1) * lLineBytes + i], bChar, iCount);

				// 已经读取像素的个数加iCount
				i += iCount;
			}
			else
			{
				// 保存当前字节
				lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar;
				
				// 已经读取像素的个数加1
				i += 1;
			}
		}
	}
	
	// 释放内存
	delete lpSrc;
	
	//*************************************************************
	// 调色板
	
	// 读调色板标志位
	file.Read(&bChar, 1);
	if (bChar != 0x0C)
	{
		// 出错
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) hDIB);
		
		// 释放内存
		::GlobalFree((HGLOBAL) hDIB);
		
		// 返回NULL。
		return NULL;
	}
	
	// 分配内存以读取编码后的象素
	lpSrc = new BYTE[768];
	
	// 计算DIB中调色板的位置
	lpDst = (BYTE *) pDIB + sizeof(BITMAPINFOHEADER);
	
	// 读取调色板
	if (file.Read(lpSrc, 768) != 768)
	{
		// 大小不对。
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) hDIB);
		
		// 释放内存
		::GlobalFree((HGLOBAL) hDIB);
		
		// 返回NULL。
		return NULL;
	}
	
	// 给调色板赋值
	for (i = 0; i < 256; i++)
	{
		lpDst[i * 4] = lpSrc[i * 3 + 2];
		lpDst[i * 4 + 1] = lpSrc[i * 3 + 1];
		lpDst[i * 4 + 2] = lpSrc[i * 3];
		lpDst[i * 4 + 3] = 0;
	}
	
	// 释放内存
	delete lpSrc;
	
	// 解除锁定
	::GlobalUnlock((HGLOBAL) hDIB);
	
	// 返回DIB句柄
	return hDIB;
}

BOOL WINAPI PlateDIB2(LPSTR lpDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine)
{

	// 指向缓存图像的指针
	LPSTR	lpDst;
//	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;
//	LPSTR	lpNewDIBBits2;
//	HLOCAL	hNewDIBBits2;

	//循环变量
	long i;
	long j;
	
	int iPlateLine[40];

	for(i=0;i<40;i++)
	{
		iPlateLine[i]=*pPlateLine;
		pPlateLine++;
	}

	//像素值
	unsigned char pixel;

	//图像中每行内的黑点个数
	long lChangeNumber;

	long lDistance;

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 暂时分配内存,以保存新图像
//	hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight);

//	if (hNewDIBBits2 == NULL)
//	{
		// 分配内存失败
//		return FALSE;
//	}
	
	// 锁定内存
//	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);

	// 拷贝源图像到缓存图像中
	lpDst = (char *)lpNewDIBBits;
	memcpy(lpNewDIBBits, lpDIBBits, lWidth * lHeight);
//	lpDst2 = (char *)lpNewDIBBits2;
//	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);

	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth; i++)
		{
			// 指向缓存图像1倒数第j行,第i个象素的指针			
			if( (j<abs(iPlateLine[0])-5) || (j>abs(iPlateLine[1])+5) )
			{
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;
				*lpDst = (BYTE)0;
			}

			else
			{
				lpDst = (char *)lpNewDIBBits + lWidth * j + i;
				if((int)*lpDst < 100)
					*lpDst = (BYTE)0;
				else
					*lpDst = (BYTE)255;
			}
		
		}
	}
/*
	for(j = abs(iPlateLine[0])-5); j <abs(iPlateLine[1])+5; j++)
	{
		for(i = 0;i <lWidth; i++)
		{
			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;
			FormerPixel = (unsigned char)*lpDst1;
			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i + 1;
			LaterPixel = (unsigned char)*lpDst1;

			if (FormerPixel != LaterPixel)
			{
				lGrayChangeNumber++;

			}

			if(pixel == 0)
			{
				lBlackNumber++;
			}
			else
			{
				lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;
				if((int)*lpDst1 < 50)
					*lpDst1 = (BYTE)0;
				else
					*lpDst1 = (BYTE)255;
			}
		
		}
	}

			// 指向源图像倒数第j行,第i个象素的指针	
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i +1;	
			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;

			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;

			}
		}
		// 记录满足条件的行的位置
		if (lGrayChangeNumber >= 10)
		{

*/
	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

//	LocalUnlock(hNewDIBBits2);
//	LocalFree(hNewDIBBits2);
	// 返回
	return TRUE;
}

BOOL WINAPI PlateDIB1(LPSTR lpDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine)
{

	// 指向缓存图像的指针
	LPSTR	lpDst1;
	LPSTR	lpDst2;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits1;
	HLOCAL	hNewDIBBits1;
	LPSTR	lpNewDIBBits2;
	HLOCAL	hNewDIBBits2;

	//循环变量
	long i;
	long j;
	
	int iPlateLine[40];

	for(i=0;i<40;i++)
	{
		iPlateLine[i]=*pPlateLine;
		pPlateLine++;
	}

	//像素值
	unsigned char pixel;

	//图像中每行内的黑点个数
	long lChangeNumber;

	long lDistance;

	// 模板高度
	int		iTempH;
	
	// 模板宽度
	int		iTempW;
	
	// 模板系数
	FLOAT	fTempC;
	
	// 模板中心元素X坐标
	int		iTempMX;
	
	// 模板中心元素Y坐标
	int		iTempMY;
	
	//模板数组
	FLOAT aTemplate[9];

	// 暂时分配内存,以保存新图像
	hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1);

	// 暂时分配内存,以保存新图像
	hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits2 == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);

	// 拷贝源图像到缓存图像中
	lpDst1 = (char *)lpNewDIBBits1;
	memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight);
	lpDst2 = (char *)lpNewDIBBits2;
	memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight);

	// 设置Sobel模板参数
	iTempW = 3;
	iTempH = 3;
	fTempC = 1.0;
	iTempMX = 1;
	iTempMY = 1;
	aTemplate[0] = -1.0;
	aTemplate[1] = -2.0;
	aTemplate[2] = -1.0;
	aTemplate[3] = 0.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 0.0;
	aTemplate[6] = 1.0;
	aTemplate[7] = 2.0;
	aTemplate[8] = 1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits1, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	// 设置Sobel模板参数
	aTemplate[0] = -1.0;
	aTemplate[1] = 0.0;
	aTemplate[2] = 1.0;
	aTemplate[3] = -2.0;
	aTemplate[4] = 0.0;
	aTemplate[5] = 2.0;
	aTemplate[6] = -1.0;
	aTemplate[7] = 0.0;
	aTemplate[8] = 1.0;

	// 调用Template()函数
	if (!Template(lpNewDIBBits2, lWidth, lHeight, 
		iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC))
	{
		return FALSE;
	}

	//求两幅缓存图像的最大值
	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth-1; i++)
		{

			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;

			// 指向缓存图像2倒数第j行,第i个象素的指针			
			lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i;
			
			if(*lpDst2 > *lpDst1)
				*lpDst1 = *lpDst2;
		
		}
	}

	for(j = 0; j <lHeight; j++)
	{
		for(i = 0;i <lWidth; i++)
		{
			// 指向缓存图像1倒数第j行,第i个象素的指针			
			if( (j<abs(iPlateLine[0])-5) || (j>abs(iPlateLine[1])+5) )
			{
				lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;
				*lpDst1 = (BYTE)0;
			}

//			else
//			{
//				lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;
//				if((int)*lpDst1 < 50)
//					*lpDst1 = (BYTE)0;
//				else
//					*lpDst1 = (BYTE)255;
//			}
		
		}
	}
/*
	for(j = abs(iPlateLine[0])-5); j <abs(iPlateLine[1])+5; j++)
	{
		for(i = 0;i <lWidth; i++)
		{
			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;
			FormerPixel = (unsigned char)*lpDst1;
			// 指向缓存图像1倒数第j行,第i个象素的指针			
			lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i + 1;
			LaterPixel = (unsigned char)*lpDst1;

			if (FormerPixel != LaterPixel)
			{
				lGrayChangeNumber++;

			}

			if(pixel == 0)
			{
				lBlackNumber++;
			}
			else
			{
				lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i;
				if((int)*lpDst1 < 50)
					*lpDst1 = (BYTE)0;
				else
					*lpDst1 = (BYTE)255;
			}
		
		}
	}

			// 指向源图像倒数第j行,第i个象素的指针	
			lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i;
			lpSrclater  = (char *)lpDIBBits + lLineBytes * j + i +1;	
			pixelformer = (unsigned char)*lpSrcformer;
			pixellater  = (unsigned char)*lpSrclater;

			if (pixelformer != pixellater)
			{
				lGrayChangeNumber++;

			}
		}
		// 记录满足条件的行的位置
		if (lGrayChangeNumber >= 10)
		{

*/
	// 复制经过模板运算后的图像到源图像
	memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits1);
	LocalFree(hNewDIBBits1);

	LocalUnlock(hNewDIBBits2);
	LocalFree(hNewDIBBits2);
	// 返回
	return TRUE;
}